diff --git a/README.md b/README.md index b857711f..644f7fa4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Part-DB/Part-DB-symfony/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Part-DB/Part-DB-symfony/?branch=master) ![PHPUnit Tests](https://github.com/Part-DB/Part-DB-symfony/workflows/PHPUnit%20Tests/badge.svg) ![Static analysis](https://github.com/Part-DB/Part-DB-symfony/workflows/Static%20analysis/badge.svg) [![codecov](https://codecov.io/gh/Part-DB/Part-DB-server/branch/master/graph/badge.svg)](https://codecov.io/gh/Part-DB/Part-DB-server) diff --git a/VERSION b/VERSION index 46b81d81..6ceb272e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.11.0 +2.11.1 diff --git a/composer.lock b/composer.lock index f25634d4..9af25525 100644 --- a/composer.lock +++ b/composer.lock @@ -616,16 +616,16 @@ }, { "name": "amphp/pipeline", - "version": "v1.2.3", + "version": "v1.2.4", "source": { "type": "git", "url": "https://github.com/amphp/pipeline.git", - "reference": "7b52598c2e9105ebcddf247fc523161581930367" + "reference": "a044733e080940d1483f56caff0c412ad6982776" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", - "reference": "7b52598c2e9105ebcddf247fc523161581930367", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/a044733e080940d1483f56caff0c412ad6982776", + "reference": "a044733e080940d1483f56caff0c412ad6982776", "shasum": "" }, "require": { @@ -637,7 +637,7 @@ "amphp/php-cs-fixer-config": "^2", "amphp/phpunit-util": "^3", "phpunit/phpunit": "^9", - "psalm/phar": "^5.18" + "psalm/phar": "6.16.1" }, "type": "library", "autoload": { @@ -671,7 +671,7 @@ ], "support": { "issues": "https://github.com/amphp/pipeline/issues", - "source": "https://github.com/amphp/pipeline/tree/v1.2.3" + "source": "https://github.com/amphp/pipeline/tree/v1.2.4" }, "funding": [ { @@ -679,7 +679,7 @@ "type": "github" } ], - "time": "2025-03-16T16:33:53+00:00" + "time": "2026-05-06T05:37:57+00:00" }, { "name": "amphp/process", @@ -977,22 +977,22 @@ }, { "name": "api-platform/doctrine-common", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/doctrine-common.git", - "reference": "2072247e3c8126d815f20324e7aaa97c2b5ee889" + "reference": "089b196c2f8e4d14333aaa3c6db33356e8fd8be0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/doctrine-common/zipball/2072247e3c8126d815f20324e7aaa97c2b5ee889", - "reference": "2072247e3c8126d815f20324e7aaa97c2b5ee889", + "url": "https://api.github.com/repos/api-platform/doctrine-common/zipball/089b196c2f8e4d14333aaa3c6db33356e8fd8be0", + "reference": "089b196c2f8e4d14333aaa3c6db33356e8fd8be0", "shasum": "" }, "require": { "api-platform/metadata": "^4.2.6", "api-platform/state": "^4.2.4", - "doctrine/collections": "^2.1", + "doctrine/collections": "^2.1 || ^3.0", "doctrine/common": "^3.2.2", "doctrine/persistence": "^3.2 || ^4.0", "php": ">=8.2" @@ -1061,22 +1061,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/doctrine-common/tree/v4.3.4" + "source": "https://github.com/api-platform/doctrine-common/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-04T13:25:58+00:00" }, { "name": "api-platform/doctrine-orm", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/doctrine-orm.git", - "reference": "3dc88ee48ffcdb6eee45ec1d3e9f25ea2aad4eaa" + "reference": "095a4c56cdd9986208100dedd5d28be50a4830ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/doctrine-orm/zipball/3dc88ee48ffcdb6eee45ec1d3e9f25ea2aad4eaa", - "reference": "3dc88ee48ffcdb6eee45ec1d3e9f25ea2aad4eaa", + "url": "https://api.github.com/repos/api-platform/doctrine-orm/zipball/095a4c56cdd9986208100dedd5d28be50a4830ba", + "reference": "095a4c56cdd9986208100dedd5d28be50a4830ba", "shasum": "" }, "require": { @@ -1150,13 +1150,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/doctrine-orm/tree/v4.3.4" + "source": "https://github.com/api-platform/doctrine-orm/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-07T11:45:31+00:00" }, { "name": "api-platform/documentation", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/documentation.git", @@ -1213,13 +1213,13 @@ ], "description": "API Platform documentation controller.", "support": { - "source": "https://github.com/api-platform/documentation/tree/v4.3.4" + "source": "https://github.com/api-platform/documentation/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/http-cache", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/http-cache.git", @@ -1293,22 +1293,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/http-cache/tree/v4.3.4" + "source": "https://github.com/api-platform/http-cache/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/hydra", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/hydra.git", - "reference": "9b0a677b21ee4f2ec255386a84bdcf1d12ea7bc4" + "reference": "317a696e396b80ba87de2560679c362923ef0a14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/hydra/zipball/9b0a677b21ee4f2ec255386a84bdcf1d12ea7bc4", - "reference": "9b0a677b21ee4f2ec255386a84bdcf1d12ea7bc4", + "url": "https://api.github.com/repos/api-platform/hydra/zipball/317a696e396b80ba87de2560679c362923ef0a14", + "reference": "317a696e396b80ba87de2560679c362923ef0a14", "shasum": "" }, "require": { @@ -1380,13 +1380,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/hydra/tree/v4.3.4" + "source": "https://github.com/api-platform/hydra/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-11T11:50:19+00:00" }, { "name": "api-platform/json-api", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/json-api.git", @@ -1462,13 +1462,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/json-api/tree/v4.3.4" + "source": "https://github.com/api-platform/json-api/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/json-schema", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/json-schema.git", @@ -1543,13 +1543,13 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/json-schema/tree/v4.3.4" + "source": "https://github.com/api-platform/json-schema/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/jsonld", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/jsonld.git", @@ -1623,22 +1623,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/jsonld/tree/v4.3.4" + "source": "https://github.com/api-platform/jsonld/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/metadata", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/metadata.git", - "reference": "e93caa26e7992ca138f2d12f79b5b25d2d091b7b" + "reference": "52b367f046c5d202629e9441aece39b0e6b37838" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/metadata/zipball/e93caa26e7992ca138f2d12f79b5b25d2d091b7b", - "reference": "e93caa26e7992ca138f2d12f79b5b25d2d091b7b", + "url": "https://api.github.com/repos/api-platform/metadata/zipball/52b367f046c5d202629e9441aece39b0e6b37838", + "reference": "52b367f046c5d202629e9441aece39b0e6b37838", "shasum": "" }, "require": { @@ -1721,13 +1721,13 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/metadata/tree/v4.3.4" + "source": "https://github.com/api-platform/metadata/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-06T12:07:59+00:00" }, { "name": "api-platform/openapi", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/openapi.git", @@ -1812,13 +1812,13 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/openapi/tree/v4.3.4" + "source": "https://github.com/api-platform/openapi/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/serializer", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/serializer.git", @@ -1906,22 +1906,22 @@ "serializer" ], "support": { - "source": "https://github.com/api-platform/serializer/tree/v4.3.4" + "source": "https://github.com/api-platform/serializer/tree/v4.3.5" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/state", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/state.git", - "reference": "dda8789e95b1627a6427edb48f9024b306fdf5ff" + "reference": "d0ac7188ae58acae4c1406f3d0a6977c50342324" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/state/zipball/dda8789e95b1627a6427edb48f9024b306fdf5ff", - "reference": "dda8789e95b1627a6427edb48f9024b306fdf5ff", + "url": "https://api.github.com/repos/api-platform/state/zipball/d0ac7188ae58acae4c1406f3d0a6977c50342324", + "reference": "d0ac7188ae58acae4c1406f3d0a6977c50342324", "shasum": "" }, "require": { @@ -1929,7 +1929,7 @@ "php": ">=8.2", "psr/container": "^1.0 || ^2.0", "symfony/deprecation-contracts": "^3.1", - "symfony/http-kernel": "^6.4 || ^7.0 || ^8.0", + "symfony/http-kernel": "^6.4.13 || ^7.0 || ^8.0", "symfony/serializer": "^6.4 || ^7.0 || ^8.0", "symfony/translation-contracts": "^3.0" }, @@ -2003,22 +2003,22 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/state/tree/v4.3.4" + "source": "https://github.com/api-platform/state/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-07T11:45:31+00:00" }, { "name": "api-platform/symfony", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/symfony.git", - "reference": "532063884e3f91a8a831322a572220cc55501a2f" + "reference": "32de5d330c9c9f647eba07981780162977b52de5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/symfony/zipball/532063884e3f91a8a831322a572220cc55501a2f", - "reference": "532063884e3f91a8a831322a572220cc55501a2f", + "url": "https://api.github.com/repos/api-platform/symfony/zipball/32de5d330c9c9f647eba07981780162977b52de5", + "reference": "32de5d330c9c9f647eba07981780162977b52de5", "shasum": "" }, "require": { @@ -2035,6 +2035,7 @@ "php": ">=8.2", "symfony/asset": "^6.4 || ^7.0 || ^8.0", "symfony/finder": "^6.4 || ^7.0 || ^8.0", + "symfony/http-kernel": "^6.4.13 || ^7.0 || ^8.0", "symfony/property-access": "^6.4 || ^7.0 || ^8.0", "symfony/property-info": "^6.4 || ^7.0 || ^8.0", "symfony/security-core": "^6.4 || ^7.0 || ^8.0", @@ -2131,28 +2132,28 @@ "symfony" ], "support": { - "source": "https://github.com/api-platform/symfony/tree/v4.3.4" + "source": "https://github.com/api-platform/symfony/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-07T11:45:31+00:00" }, { "name": "api-platform/validator", - "version": "v4.3.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/validator.git", - "reference": "22693bc3d3538af700cf274b99c834c37b1d1a68" + "reference": "6df6804799f8831469d2602d0845a0316e81fbab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/validator/zipball/22693bc3d3538af700cf274b99c834c37b1d1a68", - "reference": "22693bc3d3538af700cf274b99c834c37b1d1a68", + "url": "https://api.github.com/repos/api-platform/validator/zipball/6df6804799f8831469d2602d0845a0316e81fbab", + "reference": "6df6804799f8831469d2602d0845a0316e81fbab", "shasum": "" }, "require": { "api-platform/metadata": "^4.3", "php": ">=8.2", - "symfony/http-kernel": "^6.4 || ^7.1 || ^8.0", + "symfony/http-kernel": "^6.4.13 || ^7.1 || ^8.0", "symfony/serializer": "^6.4 || ^7.1 || ^8.0", "symfony/type-info": "^7.3 || ^8.0", "symfony/validator": "^6.4.11 || ^7.1 || ^8.0", @@ -2207,9 +2208,9 @@ "validator" ], "support": { - "source": "https://github.com/api-platform/validator/tree/v4.3.4" + "source": "https://github.com/api-platform/validator/tree/v4.3.5" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-05-07T11:45:31+00:00" }, { "name": "beberlei/assert", @@ -3986,16 +3987,16 @@ }, { "name": "doctrine/orm", - "version": "3.6.3", + "version": "3.6.5", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "e88cd591f0786089dee22b972c28aa2076df51c0" + "reference": "7e88b416153dceeb563352ca2b12465f09eea173" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/e88cd591f0786089dee22b972c28aa2076df51c0", - "reference": "e88cd591f0786089dee22b972c28aa2076df51c0", + "url": "https://api.github.com/repos/doctrine/orm/zipball/7e88b416153dceeb563352ca2b12465f09eea173", + "reference": "7e88b416153dceeb563352ca2b12465f09eea173", "shasum": "" }, "require": { @@ -4068,9 +4069,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.6.3" + "source": "https://github.com/doctrine/orm/tree/3.6.5" }, - "time": "2026-04-02T06:53:27+00:00" + "time": "2026-05-11T06:47:19+00:00" }, { "name": "doctrine/persistence", @@ -11374,16 +11375,16 @@ }, { "name": "symfony/cache", - "version": "v7.4.9", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "3860fa12a5013b48d445909c6ea07f870e10ba7c" + "reference": "8c5fbb4b5bc7a878f7ce66f1b7e29653c404984b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/3860fa12a5013b48d445909c6ea07f870e10ba7c", - "reference": "3860fa12a5013b48d445909c6ea07f870e10ba7c", + "url": "https://api.github.com/repos/symfony/cache/zipball/8c5fbb4b5bc7a878f7ce66f1b7e29653c404984b", + "reference": "8c5fbb4b5bc7a878f7ce66f1b7e29653c404984b", "shasum": "" }, "require": { @@ -11454,7 +11455,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.4.9" + "source": "https://github.com/symfony/cache/tree/v7.4.10" }, "funding": [ { @@ -11474,20 +11475,20 @@ "type": "tidelift" } ], - "time": "2026-04-29T13:21:53+00:00" + "time": "2026-05-05T08:23:16+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" + "reference": "225e8a254166bd3442e370c6f50145465db63831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/225e8a254166bd3442e370c6f50145465db63831", + "reference": "225e8a254166bd3442e370c6f50145465db63831", "shasum": "" }, "require": { @@ -11501,7 +11502,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -11534,7 +11535,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/cache-contracts/tree/v3.7.0" }, "funding": [ { @@ -11545,12 +11546,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-03-13T15:25:07+00:00" + "time": "2026-05-05T15:33:14+00:00" }, { "name": "symfony/clock", @@ -11632,16 +11637,16 @@ }, { "name": "symfony/config", - "version": "v7.4.9", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "d4a277b7a0f26487db16b264d935c617b7d994ea" + "reference": "d91b6c7cd2a8c9a9c2b8d26c8f5ed48edf99ef57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/d4a277b7a0f26487db16b264d935c617b7d994ea", - "reference": "d4a277b7a0f26487db16b264d935c617b7d994ea", + "url": "https://api.github.com/repos/symfony/config/zipball/d91b6c7cd2a8c9a9c2b8d26c8f5ed48edf99ef57", + "reference": "d91b6c7cd2a8c9a9c2b8d26c8f5ed48edf99ef57", "shasum": "" }, "require": { @@ -11687,7 +11692,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.4.9" + "source": "https://github.com/symfony/config/tree/v7.4.10" }, "funding": [ { @@ -11707,7 +11712,7 @@ "type": "tidelift" } ], - "time": "2026-04-29T14:25:20+00:00" + "time": "2026-05-03T14:20:49+00:00" }, { "name": "symfony/console", @@ -11878,16 +11883,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v7.4.9", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "27cd9f912438d07ced76008bc66cf8b0cf4de622" + "reference": "4eb0d9dfa9d4f7c59216baf49b3ed6b1fb72293d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/27cd9f912438d07ced76008bc66cf8b0cf4de622", - "reference": "27cd9f912438d07ced76008bc66cf8b0cf4de622", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4eb0d9dfa9d4f7c59216baf49b3ed6b1fb72293d", + "reference": "4eb0d9dfa9d4f7c59216baf49b3ed6b1fb72293d", "shasum": "" }, "require": { @@ -11938,7 +11943,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/v7.4.9" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.10" }, "funding": [ { @@ -11958,20 +11963,20 @@ "type": "tidelift" } ], - "time": "2026-04-30T18:38:49+00:00" + "time": "2026-05-06T11:55:30+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", "shasum": "" }, "require": { @@ -11984,7 +11989,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -12009,7 +12014,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" }, "funding": [ { @@ -12020,12 +12025,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-04-13T15:52:40+00:00" }, { "name": "symfony/doctrine-bridge", @@ -12459,16 +12468,16 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", "shasum": "" }, "require": { @@ -12482,7 +12491,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -12515,7 +12524,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" }, "funding": [ { @@ -12526,12 +12535,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { "name": "symfony/expression-language", @@ -12917,16 +12930,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v7.4.9", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "601423cc0af2eb5e8c4acdf21fed553d456ff802" + "reference": "4b9cb207d72b2e4793f28a3c62ea0865098bea20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/601423cc0af2eb5e8c4acdf21fed553d456ff802", - "reference": "601423cc0af2eb5e8c4acdf21fed553d456ff802", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/4b9cb207d72b2e4793f28a3c62ea0865098bea20", + "reference": "4b9cb207d72b2e4793f28a3c62ea0865098bea20", "shasum": "" }, "require": { @@ -13051,7 +13064,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/v7.4.9" + "source": "https://github.com/symfony/framework-bundle/tree/v7.4.10" }, "funding": [ { @@ -13071,7 +13084,7 @@ "type": "tidelift" } ], - "time": "2026-04-30T08:57:13+00:00" + "time": "2026-05-05T11:48:54+00:00" }, { "name": "symfony/http-client", @@ -13176,16 +13189,16 @@ }, { "name": "symfony/http-client-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "75d7043853a42837e68111812f4d964b01e5101c" + "reference": "4a2d00c37651c0bdc2b9e1c773487a8bf4edb12d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", - "reference": "75d7043853a42837e68111812f4d964b01e5101c", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/4a2d00c37651c0bdc2b9e1c773487a8bf4edb12d", + "reference": "4a2d00c37651c0bdc2b9e1c773487a8bf4edb12d", "shasum": "" }, "require": { @@ -13198,7 +13211,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -13234,7 +13247,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.7.0" }, "funding": [ { @@ -13245,12 +13258,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-29T11:18:49+00:00" + "time": "2026-03-06T13:17:50+00:00" }, { "name": "symfony/http-foundation", @@ -13336,16 +13353,16 @@ }, { "name": "symfony/http-kernel", - "version": "v7.4.8", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "017e76ad089bac281553389269e259e155935e1a" + "reference": "23486f59234c6fd6e8f1bec97124f3829d686627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/017e76ad089bac281553389269e259e155935e1a", - "reference": "017e76ad089bac281553389269e259e155935e1a", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/23486f59234c6fd6e8f1bec97124f3829d686627", + "reference": "23486f59234c6fd6e8f1bec97124f3829d686627", "shasum": "" }, "require": { @@ -13431,7 +13448,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/v7.4.8" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.10" }, "funding": [ { @@ -13451,7 +13468,7 @@ "type": "tidelift" } ], - "time": "2026-03-31T20:57:01+00:00" + "time": "2026-05-06T12:07:34+00:00" }, { "name": "symfony/intl", @@ -15099,16 +15116,16 @@ }, { "name": "symfony/rate-limiter", - "version": "v7.4.9", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/rate-limiter.git", - "reference": "0b0078d29f6e64b8833492e9f76a853f23fb1a81" + "reference": "778c5239c7fd6bf9b886dedf3d84ddb156ddb888" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/0b0078d29f6e64b8833492e9f76a853f23fb1a81", - "reference": "0b0078d29f6e64b8833492e9f76a853f23fb1a81", + "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/778c5239c7fd6bf9b886dedf3d84ddb156ddb888", + "reference": "778c5239c7fd6bf9b886dedf3d84ddb156ddb888", "shasum": "" }, "require": { @@ -15149,7 +15166,7 @@ "rate-limiter" ], "support": { - "source": "https://github.com/symfony/rate-limiter/tree/v7.4.9" + "source": "https://github.com/symfony/rate-limiter/tree/v7.4.10" }, "funding": [ { @@ -15169,7 +15186,7 @@ "type": "tidelift" } ], - "time": "2026-04-29T13:21:53+00:00" + "time": "2026-05-04T13:25:50+00:00" }, { "name": "symfony/routing", @@ -15710,16 +15727,16 @@ }, { "name": "symfony/serializer", - "version": "v7.4.8", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "006fd51717addf2df2bd1a64dafef6b7fab6b455" + "reference": "268c5aa6c4bd675eddd89348e7ecac292a843ddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/006fd51717addf2df2bd1a64dafef6b7fab6b455", - "reference": "006fd51717addf2df2bd1a64dafef6b7fab6b455", + "url": "https://api.github.com/repos/symfony/serializer/zipball/268c5aa6c4bd675eddd89348e7ecac292a843ddd", + "reference": "268c5aa6c4bd675eddd89348e7ecac292a843ddd", "shasum": "" }, "require": { @@ -15732,7 +15749,7 @@ "phpdocumentor/reflection-docblock": "<5.2|>=7", "phpdocumentor/type-resolver": "<1.5.1", "symfony/dependency-injection": "<6.4", - "symfony/property-access": "<6.4", + "symfony/property-access": "<6.4.31|>=7.0,<7.4.2|>=8.0,<8.0.2", "symfony/property-info": "<6.4", "symfony/type-info": "<7.2.5", "symfony/uid": "<6.4", @@ -15754,7 +15771,7 @@ "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/messenger": "^6.4|^7.0|^8.0", "symfony/mime": "^6.4|^7.0|^8.0", - "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4.31|^7.4.2|^8.0.2", "symfony/property-info": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", "symfony/type-info": "^7.2.5|^8.0", @@ -15790,7 +15807,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/v7.4.8" + "source": "https://github.com/symfony/serializer/tree/v7.4.10" }, "funding": [ { @@ -15810,20 +15827,20 @@ "type": "tidelift" } ], - "time": "2026-03-30T21:34:42+00:00" + "time": "2026-05-03T13:03:28+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.1", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", "shasum": "" }, "require": { @@ -15841,7 +15858,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -15877,7 +15894,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" }, "funding": [ { @@ -15897,7 +15914,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:30:57+00:00" + "time": "2026-03-28T09:44:51+00:00" }, { "name": "symfony/stimulus-bundle", @@ -16131,16 +16148,16 @@ }, { "name": "symfony/translation", - "version": "v7.4.8", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "33600f8489485425bfcddd0d983391038d3422e7" + "reference": "ada7578c30dd5feaa8259cff3e885069ea81ddde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/33600f8489485425bfcddd0d983391038d3422e7", - "reference": "33600f8489485425bfcddd0d983391038d3422e7", + "url": "https://api.github.com/repos/symfony/translation/zipball/ada7578c30dd5feaa8259cff3e885069ea81ddde", + "reference": "ada7578c30dd5feaa8259cff3e885069ea81ddde", "shasum": "" }, "require": { @@ -16207,7 +16224,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.8" + "source": "https://github.com/symfony/translation/tree/v7.4.10" }, "funding": [ { @@ -16227,20 +16244,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-05-06T11:19:24+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.1", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977" + "reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/0ab302977a952b42fd51475c4ebac81f8da0a95d", + "reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d", "shasum": "" }, "require": { @@ -16253,7 +16270,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -16289,7 +16306,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.0" }, "funding": [ { @@ -16309,7 +16326,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { "name": "symfony/twig-bridge", @@ -16863,16 +16880,16 @@ }, { "name": "symfony/validator", - "version": "v7.4.9", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "d3bb3dcfbaa26b5782196819dac2e1097d5fae2c" + "reference": "c76458623af9a3fe3b2e5b09b36453f334c2a361" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/d3bb3dcfbaa26b5782196819dac2e1097d5fae2c", - "reference": "d3bb3dcfbaa26b5782196819dac2e1097d5fae2c", + "url": "https://api.github.com/repos/symfony/validator/zipball/c76458623af9a3fe3b2e5b09b36453f334c2a361", + "reference": "c76458623af9a3fe3b2e5b09b36453f334c2a361", "shasum": "" }, "require": { @@ -16943,7 +16960,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.4.9" + "source": "https://github.com/symfony/validator/tree/v7.4.10" }, "funding": [ { @@ -16963,7 +16980,7 @@ "type": "tidelift" } ], - "time": "2026-04-30T15:35:16+00:00" + "time": "2026-05-05T15:30:56+00:00" }, { "name": "symfony/var-dumper", @@ -17298,16 +17315,16 @@ }, { "name": "symfony/yaml", - "version": "v7.4.8", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "c58fdf7b3d6c2995368264c49e4e8b05bcff2883" + "reference": "c660d6538545a3e8e65a5621ee3d7a6d352892c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/c58fdf7b3d6c2995368264c49e4e8b05bcff2883", - "reference": "c58fdf7b3d6c2995368264c49e4e8b05bcff2883", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c660d6538545a3e8e65a5621ee3d7a6d352892c7", + "reference": "c660d6538545a3e8e65a5621ee3d7a6d352892c7", "shasum": "" }, "require": { @@ -17350,7 +17367,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.8" + "source": "https://github.com/symfony/yaml/tree/v7.4.10" }, "funding": [ { @@ -17370,29 +17387,29 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-05-05T08:01:55+00:00" }, { "name": "symplify/easy-coding-standard", - "version": "13.1.2", + "version": "13.1.3", "source": { "type": "git", "url": "https://github.com/easy-coding-standard/ecs.git", - "reference": "6d22473d1f36945884d8cb291777166020a47770" + "reference": "d894d088d7ebb9326f9eed28bf251481c813b89f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/easy-coding-standard/ecs/zipball/6d22473d1f36945884d8cb291777166020a47770", - "reference": "6d22473d1f36945884d8cb291777166020a47770", + "url": "https://api.github.com/repos/easy-coding-standard/ecs/zipball/d894d088d7ebb9326f9eed28bf251481c813b89f", + "reference": "d894d088d7ebb9326f9eed28bf251481c813b89f", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "friendsofphp/php-cs-fixer": "<3.92.4", + "friendsofphp/php-cs-fixer": "<3.95.1", "phpcsstandards/php_codesniffer": "<4.0.1", - "symplify/coding-standard": "<12.1" + "symplify/coding-standard": "<13.0" }, "suggest": { "ext-dom": "Needed to support checkstyle output format in class CheckstyleOutputFormatter" @@ -17418,20 +17435,9 @@ "static analysis" ], "support": { - "issues": "https://github.com/easy-coding-standard/ecs/issues", - "source": "https://github.com/easy-coding-standard/ecs/tree/13.1.2" + "source": "https://github.com/easy-coding-standard/ecs/tree/13.1.3" }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2026-05-03T22:05:09+00:00" + "time": "2026-05-04T21:45:57+00:00" }, { "name": "tecnickcom/tc-lib-barcode", @@ -19467,16 +19473,16 @@ }, { "name": "phpstan/phpstan-doctrine", - "version": "2.0.21", + "version": "2.0.22", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "81dac0ee4363c2359128aec844df31efb215dddc" + "reference": "e87516b034749432d51653c0147e053e476e8c53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/81dac0ee4363c2359128aec844df31efb215dddc", - "reference": "81dac0ee4363c2359128aec844df31efb215dddc", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/e87516b034749432d51653c0147e053e476e8c53", + "reference": "e87516b034749432d51653c0147e053e476e8c53", "shasum": "" }, "require": { @@ -19510,6 +19516,7 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.6.20", "ramsey/uuid": "^4.2", + "shipmonk/name-collision-detector": "^2.1", "symfony/cache": "^5.4", "symfony/uid": "^5.4 || ^6.4 || ^7.3" }, @@ -19537,9 +19544,9 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.21" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.22" }, - "time": "2026-04-17T13:00:39+00:00" + "time": "2026-05-09T08:10:48+00:00" }, { "name": "phpstan/phpstan-strict-rules", @@ -19594,16 +19601,16 @@ }, { "name": "phpstan/phpstan-symfony", - "version": "2.0.15", + "version": "2.0.17", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "9b85ab476969b87bbe2253b69e265a9359b2f395" + "reference": "fdd0cb5f08d1980c612d6f259d825ea644ed03f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/9b85ab476969b87bbe2253b69e265a9359b2f395", - "reference": "9b85ab476969b87bbe2253b69e265a9359b2f395", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/fdd0cb5f08d1980c612d6f259d825ea644ed03f4", + "reference": "fdd0cb5f08d1980c612d6f259d825ea644ed03f4", "shasum": "" }, "require": { @@ -19662,9 +19669,9 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.15" + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.17" }, - "time": "2026-02-26T10:15:59+00:00" + "time": "2026-05-10T08:14:07+00:00" }, { "name": "phpunit/php-code-coverage", @@ -20189,12 +20196,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "2221f6ef09e87784e78e188aadd8f7e3a50e679a" + "reference": "d7895ee3af79168d03a6b7d37caf0f746d79bfb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/2221f6ef09e87784e78e188aadd8f7e3a50e679a", - "reference": "2221f6ef09e87784e78e188aadd8f7e3a50e679a", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/d7895ee3af79168d03a6b7d37caf0f746d79bfb1", + "reference": "d7895ee3af79168d03a6b7d37caf0f746d79bfb1", "shasum": "" }, "conflict": { @@ -20254,14 +20261,14 @@ "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": "<=3.371.3", "ayacoo/redirect-tab": "<2.1.2|>=3,<3.1.7|>=4,<4.0.5", - "azuracast/azuracast": "<=0.23.3", + "azuracast/azuracast": "<=0.23.5", "b13/seo_basics": "<0.8.2", "backdrop/backdrop": "<=1.32", "backpack/crud": "<3.4.9", "backpack/filemanager": "<2.0.2|>=3,<3.0.9", "bacula-web/bacula-web": "<9.7.1", "badaso/core": "<=2.9.11", - "bagisto/bagisto": "<2.3.10", + "bagisto/bagisto": "<=2.3.15", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "barryvdh/laravel-translation-manager": "<0.6.8", @@ -20309,7 +20316,7 @@ "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1", "chrome-php/chrome": "<1.14", - "ci4-cms-erp/ci4ms": "<=0.31.6", + "ci4-cms-erp/ci4ms": "<=0.31.7", "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", "ckeditor/ckeditor": "<4.25", "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", @@ -20342,7 +20349,7 @@ "cpsit/typo3-mailqueue": "<0.4.5|>=0.5,<0.5.2", "craftcms/aws-s3": ">=2.0.2,<=2.2.4", "craftcms/azure-blob": ">=2.0.0.0-beta1,<=2.1", - "craftcms/cms": "<=4.17.8|>=5,<5.9.15", + "craftcms/cms": "<4.17.12|>=5,<5.9.18", "craftcms/commerce": ">=4,<4.11|>=5,<5.6", "craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1", "craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21", @@ -20361,6 +20368,7 @@ "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", "dcat/laravel-admin": "<=2.1.3|==2.2.0.0-beta|==2.2.2.0-beta", + "dedoc/scramble": ">=0.13.2,<0.13.22", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", "desperado/xml-bundle": "<=0.1.7", @@ -20382,7 +20390,7 @@ "doctrine/mongodb-odm": "<1.0.2", "doctrine/mongodb-odm-bundle": "<3.0.1", "doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<=22.0.4", + "dolibarr/dolibarr": "<=23.0.2", "dompdf/dompdf": "<2.0.4", "doublethreedigital/guest-entries": "<3.1.2", "dreamfactory/df-core": "<1.0.4", @@ -20461,7 +20469,7 @@ "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", "ezyang/htmlpurifier": "<=4.2", "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<2025.81", + "facturascripts/facturascripts": "<=2025.92|>=2026,<=2026.1", "fastly/magento2": "<1.2.26", "feehi/cms": "<=2.1.1", "feehi/feehicms": "<=2.1.1", @@ -20484,6 +20492,7 @@ "flarum/nicknames": "<1.8.3", "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", "flarum/tags": "<=0.1.0.0-beta13", + "flightphp/core": "<3.18.1", "floriangaerber/magnesium": "<0.3.1", "fluidtypo3/vhs": "<5.1.1", "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", @@ -20507,13 +20516,15 @@ "froxlor/froxlor": "<2.3.6", "frozennode/administrator": "<=5.0.12", "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=7.1.0.0-RC4", + "funadmin/funadmin": "<=7.1.0.0-RC6", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", "georgringer/news": "<1.3.3", "geshi/geshi": "<=1.0.9.1", "getformwork/formwork": "<=2.3.3", - "getgrav/grav": "<1.11.0.0-beta1", + "getgrav/grav": "<2.0.0.0-beta4", + "getgrav/grav-plugin-api": "<1.0.0.0-beta15", + "getgrav/grav-plugin-form": "<9.1", "getkirby/cms": "<4.9|>=5,<5.4", "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", "getkirby/panel": "<2.5.14", @@ -20573,6 +20584,7 @@ "innologi/typo3-appointments": "<2.0.6", "intelliants/subrion": "<4.2.2", "inter-mediator/inter-mediator": "==5.5", + "intercom/intercom-php": "==5.0.2", "invoiceninja/invoiceninja": "<5.13.4", "ipl/web": "<=0.13", "islandora/crayfish": "<4.1", @@ -20612,7 +20624,7 @@ "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3.4.1", - "kimai/kimai": "<2.54", + "kimai/kimai": "<=2.55", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<=1.4.2", @@ -20680,6 +20692,7 @@ "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", "mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7", "maximebf/debugbar": "<1.19", + "mckenziearts/livewire-markdown-editor": "<1.3", "mdanter/ecc": "<2", "mediawiki/abuse-filter": "<1.39.9|>=1.40,<1.41.3|>=1.42,<1.42.2", "mediawiki/cargo": "<3.8.3", @@ -20704,6 +20717,7 @@ "miniorange/miniorange-saml": "<1.4.3", "miraheze/ts-portal": "<=33", "mittwald/typo3_forum": "<1.2.1", + "mix/mix": ">=2,<=2.2.17", "mobiledetect/mobiledetectlib": "<2.8.32", "modx/revolution": "<=3.1", "mojo42/jirafeau": "<4.4", @@ -20723,6 +20737,7 @@ "munkireport/softwareupdate": "<1.6", "mustache/mustache": ">=2,<2.14.1", "mwdelaney/wp-enable-svg": "<=0.2", + "nabeel/phpvms": "<7.0.6", "namshi/jose": "<2.2", "nasirkhan/laravel-starter": "<11.11", "nategood/httpful": "<1", @@ -20763,7 +20778,7 @@ "open-web-analytics/open-web-analytics": "<1.8.1", "opencart/opencart": ">=0", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<20.17", + "openmage/magento-lts": "<=20.17", "opensolutions/vimbadmin": "<=3.0.15", "opensource-workshop/connect-cms": "<1.41.1|>=2,<2.41.1", "orchid/platform": ">=8,<14.43", @@ -20806,13 +20821,13 @@ "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<5.2.2", - "phpmyfaq/phpmyfaq": "<=4.1", + "phpmyfaq/phpmyfaq": "<=4.1.1", "phpoffice/common": "<0.2.9", "phpoffice/math": "<=0.2", "phpoffice/phpexcel": "<=1.8.2", "phpoffice/phpspreadsheet": "<=1.30.3|>=2,<=2.1.15|>=2.2,<=2.4.4|>=3,<=3.10.4|>=4,<=5.6", "phppgadmin/phppgadmin": "<=7.13", - "phpseclib/phpseclib": "<2.0.53|>=3,<3.0.51", + "phpseclib/phpseclib": "<=2.0.53|>=3,<=3.0.51", "phpservermon/phpservermon": "<3.6", "phpsysinfo/phpsysinfo": "<3.4.3", "phpunit/phpunit": "<8.5.52|>=9,<9.6.33|>=10,<10.5.62|>=11,<11.5.50|>=12,<12.5.8|>=12.5.21,<12.5.22|>=13.1.5,<13.1.6", @@ -20828,7 +20843,7 @@ "pimcore/demo": "<10.3", "pimcore/ecommerce-framework-bundle": "<1.0.10", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<=11.5.14.1|>=12,<12.3.3", + "pimcore/pimcore": "<=11.5.14.1|>=12,<12.3.3|==12.3.3", "pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1", "piwik/piwik": "<1.11", "pixelfed/pixelfed": "<0.12.5", @@ -20842,7 +20857,7 @@ "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.2.5|>=9.0.0.0-alpha1,<9.1", + "prestashop/prestashop": "<8.2.6|>=9,<9.1.1", "prestashop/productcomments": "<5.0.2", "prestashop/ps_checkout": "<5.3", "prestashop/ps_contactinfo": "<=3.3.2", @@ -20906,7 +20921,7 @@ "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", "shopxo/shopxo": "<=6.4", - "showdoc/showdoc": "<2.10.4", + "showdoc/showdoc": "<3.8.1", "shuchkin/simplexlsx": ">=1.0.12,<1.1.13", "silverstripe-australia/advancedreports": ">=1,<=2", "silverstripe/admin": "<1.13.19|>=2,<2.1.8", @@ -20945,7 +20960,7 @@ "slim/slim": "<2.6", "slub/slub-events": "<3.0.3", "smarty/smarty": "<4.5.3|>=5,<5.1.1", - "snipe/snipe-it": "<8.3.7", + "snipe/snipe-it": "<8.4.1", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6", @@ -20963,9 +20978,9 @@ "starcitizentools/short-description": ">=4,<4.0.1", "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1", "starcitizenwiki/embedvideo": "<=4", - "statamic/cms": "<5.73.20|>=6,<6.13", + "statamic/cms": "<5.73.21|>=6,<6.15", "stormpath/sdk": "<9.9.99", - "studio-42/elfinder": "<2.1.67", + "studio-42/elfinder": "<=2.1.67", "studiomitte/friendlycaptcha": "<0.1.4", "subhh/libconnect": "<7.0.8|>=8,<8.1", "sukohi/surpass": "<1", @@ -21037,7 +21052,7 @@ "thelia/thelia": ">=2.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<6.0.8", - "thorsten/phpmyfaq": "<4.1.1", + "thorsten/phpmyfaq": "<=4.1.1", "tikiwiki/tiki-manager": "<=17.1", "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", "tinymce/tinymce": "<7.2", @@ -21110,7 +21125,7 @@ "wallabag/wallabag": "<2.6.11", "wanglelecc/laracms": "<=1.0.3", "wapplersystems/a21glossary": "<=0.4.10", - "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9|>=5.2,<5.2.4", + "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9|>=5.2,<5.2.4|>=5.3,<5.3.1", "web-auth/webauthn-lib": ">=4.5,<4.9|>=5.2,<5.2.4", "web-auth/webauthn-symfony-bundle": ">=5.2,<5.2.4", "web-feet/coastercms": "==5.5", @@ -21119,7 +21134,7 @@ "webcoast/deferred-image-processing": "<1.0.2", "webklex/laravel-imap": "<5.3", "webklex/php-imap": "<5.3", - "webonyx/graphql-php": "<=15.31.4", + "webonyx/graphql-php": "<=15.32.2", "webpa/webpa": "<3.1.2", "webreinvent/vaahcms": "<=2.3.1", "wikibase/wikibase": "<=1.39.3", @@ -21239,7 +21254,7 @@ "type": "tidelift" } ], - "time": "2026-04-30T21:24:12+00:00" + "time": "2026-05-11T16:56:44+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/reference.php b/config/reference.php index e1304d43..b561084b 100644 --- a/config/reference.php +++ b/config/reference.php @@ -193,40 +193,40 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * workflows?: bool|array{ * enabled?: bool|Param, // Default: false * workflows?: array, - * definition_validators?: list, - * support_strategy?: scalar|Param|null, - * initial_marking?: backed-enum|string|list, - * events_to_dispatch?: null|list, - * places?: string|list, - * }>, - * transitions?: list, - * to?: backed-enum|string|list, - * weight?: int|Param, // Default: 1 - * metadata?: array, - * }>, + * audit_trail?: bool|array{ + * enabled?: bool|Param, // Default: false + * }, + * type?: "workflow"|"state_machine"|Param, // Default: "state_machine" + * marking_store?: array{ + * type?: "method"|Param, + * property?: scalar|Param|null, + * service?: scalar|Param|null, + * }, + * supports?: string|list, + * definition_validators?: list, + * support_strategy?: scalar|Param|null, + * initial_marking?: \BackedEnum|string|list, + * events_to_dispatch?: null|list, + * places?: string|list, * }>, + * transitions?: list, + * to?: \BackedEnum|string|list, + * weight?: int|Param, // Default: 1 + * metadata?: array, + * }>, + * metadata?: array, + * }>, * }, * router?: bool|array{ // Router configuration * enabled?: bool|Param, // Default: false @@ -273,14 +273,14 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * base_path?: scalar|Param|null, // Default: "" * base_urls?: string|list, * packages?: array, - * }>, + * strict_mode?: bool|Param, // Throw an exception if an entry is missing from the manifest.json. // Default: false + * version_strategy?: scalar|Param|null, // Default: null + * version?: scalar|Param|null, + * version_format?: scalar|Param|null, // Default: null + * json_manifest_path?: scalar|Param|null, // Default: null + * base_path?: scalar|Param|null, // Default: "" + * base_urls?: string|list, + * }>, * }, * asset_mapper?: bool|array{ // Asset Mapper configuration * enabled?: bool|Param, // Default: false @@ -318,16 +318,16 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * localizable_html_attributes?: list, * }, * providers?: array, - * locales?: list, - * }>, + * dsn?: scalar|Param|null, + * domains?: list, + * locales?: list, + * }>, * globals?: array, - * domain?: string|Param, - * }>, + * value?: mixed, + * message?: string|Param, + * parameters?: array, + * domain?: string|Param, + * }>, * }, * validation?: bool|array{ // Validation configuration * enabled?: bool|Param, // Default: true @@ -345,8 +345,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * disable_translation?: bool|Param, // Default: false * auto_mapping?: array, - * }>, + * services?: list, + * }>, * }, * annotations?: bool|array{ * enabled?: bool|Param, // Default: false @@ -362,11 +362,11 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * default_context?: array, * named_serializers?: array, - * include_built_in_normalizers?: bool|Param, // Whether to include the built-in normalizers // Default: true - * include_built_in_encoders?: bool|Param, // Whether to include the built-in encoders // Default: true - * }>, + * name_converter?: scalar|Param|null, + * default_context?: array, + * include_built_in_normalizers?: bool|Param, // Whether to include the built-in normalizers // Default: true + * include_built_in_encoders?: bool|Param, // Whether to include the built-in encoders // Default: true + * }>, * }, * property_access?: bool|array{ // Property access configuration * enabled?: bool|Param, // Default: true @@ -396,24 +396,24 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * default_doctrine_dbal_provider?: scalar|Param|null, // Default: "database_connection" * default_pdo_provider?: scalar|Param|null, // Default: null * pools?: array, - * tags?: scalar|Param|null, // Default: null - * public?: bool|Param, // Default: false - * default_lifetime?: scalar|Param|null, // Default lifetime of the pool. - * provider?: scalar|Param|null, // Overwrite the setting from the default provider for this adapter. - * early_expiration_message_bus?: scalar|Param|null, - * clearer?: scalar|Param|null, - * }>, + * adapters?: string|list, + * tags?: scalar|Param|null, // Default: null + * public?: bool|Param, // Default: false + * default_lifetime?: scalar|Param|null, // Default lifetime of the pool. + * provider?: scalar|Param|null, // Overwrite the setting from the default provider for this adapter. + * early_expiration_message_bus?: scalar|Param|null, + * clearer?: scalar|Param|null, + * }>, * }, * php_errors?: array{ // PHP errors handling configuration * log?: mixed, // Use the application logger instead of the PHP logger for logging PHP errors. // Default: true * throw?: bool|Param, // Throw PHP errors as \ErrorException instances. // Default: true * }, * exceptions?: array, + * log_level?: scalar|Param|null, // The level of log message. Null to let Symfony decide. // Default: null + * status_code?: scalar|Param|null, // The status code of the response. Null or 0 to let Symfony decide. // Default: null + * log_channel?: scalar|Param|null, // The channel of log message. Null to let Symfony decide. // Default: null + * }>, * web_link?: bool|array{ // Web links configuration * enabled?: bool|Param, // Default: true * }, @@ -428,8 +428,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * messenger?: bool|array{ // Messenger configuration * enabled?: bool|Param, // Default: false * routing?: array, - * }>, + * senders?: list, + * }>, * serializer?: array{ * default_serializer?: scalar|Param|null, // Service id to use as the default serializer for the transports. // Default: "messenger.transport.native_php_serializer" * symfony_serializer?: array{ @@ -438,34 +438,34 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * }, * transports?: array, - * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null - * retry_strategy?: string|array{ - * service?: scalar|Param|null, // Service id to override the retry strategy entirely. // Default: null - * max_retries?: int|Param, // Default: 3 - * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 - * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries)). // Default: 2 - * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 - * jitter?: float|Param, // Randomness to apply to the delay (between 0 and 1). // Default: 0.1 - * }, - * rate_limiter?: scalar|Param|null, // Rate limiter name to use when processing messages. // Default: null - * }>, + * dsn?: scalar|Param|null, + * serializer?: scalar|Param|null, // Service id of a custom serializer to use. // Default: null + * options?: array, + * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null + * retry_strategy?: string|array{ + * service?: scalar|Param|null, // Service id to override the retry strategy entirely. // Default: null + * max_retries?: int|Param, // Default: 3 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries)). // Default: 2 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 + * jitter?: float|Param, // Randomness to apply to the delay (between 0 and 1). // Default: 0.1 + * }, + * rate_limiter?: scalar|Param|null, // Rate limiter name to use when processing messages. // Default: null + * }>, * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null * stop_worker_on_signals?: int|string|list, * default_bus?: scalar|Param|null, // Default: null * buses?: array, - * }>, + * default_middleware?: bool|string|array{ + * enabled?: bool|Param, // Default: true + * allow_no_handlers?: bool|Param, // Default: false + * allow_no_senders?: bool|Param, // Default: true + * }, + * middleware?: string|list, * }>, + * }>, * }, * scheduler?: bool|array{ // Scheduler configuration * enabled?: bool|Param, // Default: false @@ -511,9 +511,9 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * enabled?: bool|Param, // Default: false * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null * http_codes?: int|string|array, - * }>, + * code?: int|Param, + * methods?: string|list, + * }>, * max_retries?: int|Param, // Default: 3 * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 @@ -523,57 +523,57 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * mock_response_factory?: scalar|Param|null, // The id of the service that should generate mock responses. It should be either an invokable or an iterable. * scoped_clients?: array, - * headers?: array, - * max_redirects?: int|Param, // The maximum number of redirects to follow. - * http_version?: scalar|Param|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. - * resolve?: array, - * proxy?: scalar|Param|null, // The URL of the proxy to pass requests through or null for automatic detection. - * no_proxy?: scalar|Param|null, // A comma separated list of hosts that do not require a proxy to be reached. - * timeout?: float|Param, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. - * max_duration?: float|Param, // The maximum execution time for the request+response as a whole. - * bindto?: scalar|Param|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. - * verify_peer?: bool|Param, // Indicates if the peer should be verified in a TLS context. - * verify_host?: bool|Param, // Indicates if the host should exist as a certificate common name. - * cafile?: scalar|Param|null, // A certificate authority file. - * capath?: scalar|Param|null, // A directory that contains multiple certificate authority files. - * local_cert?: scalar|Param|null, // A PEM formatted certificate file. - * local_pk?: scalar|Param|null, // A private key file. - * passphrase?: scalar|Param|null, // The passphrase used to encrypt the "local_pk" file. - * ciphers?: scalar|Param|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...). - * peer_fingerprint?: array{ // Associative array: hashing algorithm => hash(es). - * sha1?: mixed, - * pin-sha256?: mixed, - * md5?: mixed, - * }, - * crypto_method?: scalar|Param|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. - * extra?: array, - * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null - * caching?: bool|array{ // Caching configuration. - * enabled?: bool|Param, // Default: false - * cache_pool?: string|Param, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" - * shared?: bool|Param, // Indicates whether the cache is shared (public) or private. // Default: true - * max_ttl?: int|Param, // The maximum TTL (in seconds) allowed for cached responses. Null means no cap. // Default: null - * }, - * retry_failed?: bool|array{ - * enabled?: bool|Param, // Default: false - * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null - * http_codes?: int|string|array, - * }>, - * max_retries?: int|Param, // Default: 3 - * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 - * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 - * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 - * jitter?: float|Param, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 - * }, - * }>, + * scope?: scalar|Param|null, // The regular expression that the request URL must match before adding the other options. When none is provided, the base URI is used instead. + * base_uri?: scalar|Param|null, // The URI to resolve relative URLs, following rules in RFC 3985, section 2. + * auth_basic?: scalar|Param|null, // An HTTP Basic authentication "username:password". + * auth_bearer?: scalar|Param|null, // A token enabling HTTP Bearer authorization. + * auth_ntlm?: scalar|Param|null, // A "username:password" pair to use Microsoft NTLM authentication (requires the cURL extension). + * query?: array, + * headers?: array, + * max_redirects?: int|Param, // The maximum number of redirects to follow. + * http_version?: scalar|Param|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. + * resolve?: array, + * proxy?: scalar|Param|null, // The URL of the proxy to pass requests through or null for automatic detection. + * no_proxy?: scalar|Param|null, // A comma separated list of hosts that do not require a proxy to be reached. + * timeout?: float|Param, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. + * max_duration?: float|Param, // The maximum execution time for the request+response as a whole. + * bindto?: scalar|Param|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. + * verify_peer?: bool|Param, // Indicates if the peer should be verified in a TLS context. + * verify_host?: bool|Param, // Indicates if the host should exist as a certificate common name. + * cafile?: scalar|Param|null, // A certificate authority file. + * capath?: scalar|Param|null, // A directory that contains multiple certificate authority files. + * local_cert?: scalar|Param|null, // A PEM formatted certificate file. + * local_pk?: scalar|Param|null, // A private key file. + * passphrase?: scalar|Param|null, // The passphrase used to encrypt the "local_pk" file. + * ciphers?: scalar|Param|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...). + * peer_fingerprint?: array{ // Associative array: hashing algorithm => hash(es). + * sha1?: mixed, + * pin-sha256?: mixed, + * md5?: mixed, + * }, + * crypto_method?: scalar|Param|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. + * extra?: array, + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null + * caching?: bool|array{ // Caching configuration. + * enabled?: bool|Param, // Default: false + * cache_pool?: string|Param, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" + * shared?: bool|Param, // Indicates whether the cache is shared (public) or private. // Default: true + * max_ttl?: int|Param, // The maximum TTL (in seconds) allowed for cached responses. Null means no cap. // Default: null + * }, + * retry_failed?: bool|array{ + * enabled?: bool|Param, // Default: false + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null + * http_codes?: int|string|array, + * }>, + * max_retries?: int|Param, // Default: 3 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 + * jitter?: float|Param, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 + * }, + * }>, * }, * mailer?: bool|array{ // Mailer configuration * enabled?: bool|Param, // Default: true @@ -586,8 +586,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * allowed_recipients?: string|list, * }, * headers?: array, + * value?: mixed, + * }>, * dkim_signer?: bool|array{ // DKIM signer configuration * enabled?: bool|Param, // Default: false * key?: scalar|Param|null, // Key content, or path to key (in PEM format with the `file://` prefix) // Default: "" @@ -624,25 +624,25 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * notification_on_failed_messages?: bool|Param, // Default: false * channel_policy?: array>, * admin_recipients?: list, + * email?: scalar|Param|null, + * phone?: scalar|Param|null, // Default: "" + * }>, * }, * rate_limiter?: bool|array{ // Rate limiter configuration * enabled?: bool|Param, // Default: true * limiters?: array, - * limit?: int|Param, // The maximum allowed hits in a fixed interval or burst. - * interval?: scalar|Param|null, // Configures the fixed interval if "policy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). - * rate?: array{ // Configures the fill rate if "policy" is set to "token_bucket". - * interval?: scalar|Param|null, // Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). - * amount?: int|Param, // Amount of tokens to add each interval. // Default: 1 - * }, - * }>, + * lock_factory?: scalar|Param|null, // The service ID of the lock factory used by this limiter (or null to disable locking). // Default: "auto" + * cache_pool?: scalar|Param|null, // The cache pool to use for storing the current limiter state. // Default: "cache.rate_limiter" + * storage_service?: scalar|Param|null, // The service ID of a custom storage implementation, this precedes any configured "cache_pool". // Default: null + * policy?: "fixed_window"|"token_bucket"|"sliding_window"|"compound"|"no_limit"|Param, // The algorithm to be used by this limiter. + * limiters?: string|list, + * limit?: int|Param, // The maximum allowed hits in a fixed interval or burst. + * interval?: scalar|Param|null, // Configures the fixed interval if "policy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). + * rate?: array{ // Configures the fill rate if "policy" is set to "token_bucket". + * interval?: scalar|Param|null, // Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). + * amount?: int|Param, // Amount of tokens to add each interval. // Default: 1 + * }, + * }>, * }, * uid?: bool|array{ // Uid configuration * enabled?: bool|Param, // Default: true @@ -655,33 +655,33 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * html_sanitizer?: bool|array{ // HtmlSanitizer configuration * enabled?: bool|Param, // Default: false * sanitizers?: array, - * block_elements?: string|list, - * drop_elements?: string|list, - * allow_attributes?: array, - * drop_attributes?: array, - * force_attributes?: array>, - * force_https_urls?: bool|Param, // Transforms URLs using the HTTP scheme to use the HTTPS scheme instead. // Default: false - * allowed_link_schemes?: string|list, - * allowed_link_hosts?: null|string|list, - * allow_relative_links?: bool|Param, // Allows relative URLs to be used in links href attributes. // Default: false - * allowed_media_schemes?: string|list, - * allowed_media_hosts?: null|string|list, - * allow_relative_medias?: bool|Param, // Allows relative URLs to be used in media source attributes (img, audio, video, ...). // Default: false - * with_attribute_sanitizers?: string|list, - * without_attribute_sanitizers?: string|list, - * max_input_length?: int|Param, // The maximum length allowed for the sanitized input. // Default: 0 - * }>, + * allow_safe_elements?: bool|Param, // Allows "safe" elements and attributes. // Default: false + * allow_static_elements?: bool|Param, // Allows all static elements and attributes from the W3C Sanitizer API standard. // Default: false + * allow_elements?: array, + * block_elements?: string|list, + * drop_elements?: string|list, + * allow_attributes?: array, + * drop_attributes?: array, + * force_attributes?: array>, + * force_https_urls?: bool|Param, // Transforms URLs using the HTTP scheme to use the HTTPS scheme instead. // Default: false + * allowed_link_schemes?: string|list, + * allowed_link_hosts?: null|string|list, + * allow_relative_links?: bool|Param, // Allows relative URLs to be used in links href attributes. // Default: false + * allowed_media_schemes?: string|list, + * allowed_media_hosts?: null|string|list, + * allow_relative_medias?: bool|Param, // Allows relative URLs to be used in media source attributes (img, audio, video, ...). // Default: false + * with_attribute_sanitizers?: string|list, + * without_attribute_sanitizers?: string|list, + * max_input_length?: int|Param, // The maximum length allowed for the sanitized input. // Default: 0 + * }>, * }, * webhook?: bool|array{ // Webhook configuration * enabled?: bool|Param, // Default: false * message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus" * routing?: array, + * service?: scalar|Param|null, + * secret?: scalar|Param|null, // Default: "" + * }>, * }, * remote-event?: bool|array{ // RemoteEvent configuration * enabled?: bool|Param, // Default: false @@ -694,11 +694,62 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * dbal?: array{ * default_connection?: scalar|Param|null, * types?: array, + * class?: scalar|Param|null, + * commented?: bool|Param, // Deprecated: The doctrine-bundle type commenting features were removed; the corresponding config parameter was deprecated in 2.0 and will be dropped in 3.0. + * }>, * driver_schemes?: array, * connections?: array, + * mapping_types?: array, + * default_table_options?: array, + * schema_manager_factory?: scalar|Param|null, // Default: "doctrine.dbal.default_schema_manager_factory" + * result_cache?: scalar|Param|null, + * slaves?: array, - * mapping_types?: array, - * default_table_options?: array, - * schema_manager_factory?: scalar|Param|null, // Default: "doctrine.dbal.default_schema_manager_factory" - * result_cache?: scalar|Param|null, - * slaves?: array, - * replicas?: array, * }>, + * replicas?: array, + * }>, * }, * orm?: array{ * default_entity_manager?: scalar|Param|null, @@ -828,94 +828,94 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * evict_cache?: bool|Param, // Set to true to fetch the entity from the database instead of using the cache, if any // Default: false * }, * entity_managers?: array, - * }>, + * query_cache_driver?: string|array{ + * type?: scalar|Param|null, // Default: null + * id?: scalar|Param|null, + * pool?: scalar|Param|null, + * }, + * metadata_cache_driver?: string|array{ + * type?: scalar|Param|null, // Default: null + * id?: scalar|Param|null, + * pool?: scalar|Param|null, + * }, + * result_cache_driver?: string|array{ + * type?: scalar|Param|null, // Default: null + * id?: scalar|Param|null, + * pool?: scalar|Param|null, + * }, + * entity_listeners?: array{ + * entities?: array, + * }>, + * }>, + * }, + * connection?: scalar|Param|null, + * class_metadata_factory_name?: scalar|Param|null, // Default: "Doctrine\\ORM\\Mapping\\ClassMetadataFactory" + * default_repository_class?: scalar|Param|null, // Default: "Doctrine\\ORM\\EntityRepository" + * auto_mapping?: scalar|Param|null, // Default: false + * naming_strategy?: scalar|Param|null, // Default: "doctrine.orm.naming_strategy.default" + * quote_strategy?: scalar|Param|null, // Default: "doctrine.orm.quote_strategy.default" + * typed_field_mapper?: scalar|Param|null, // Default: "doctrine.orm.typed_field_mapper.default" + * entity_listener_resolver?: scalar|Param|null, // Default: null + * fetch_mode_subselect_batch_size?: scalar|Param|null, + * repository_factory?: scalar|Param|null, // Default: "doctrine.orm.container_repository_factory" + * schema_ignore_classes?: list, + * report_fields_where_declared?: bool|Param, // Set to "true" to opt-in to the new mapping driver mode that was added in Doctrine ORM 2.16 and will be mandatory in ORM 3.0. See https://github.com/doctrine/orm/pull/10455. // Default: true + * validate_xml_mapping?: bool|Param, // Set to "true" to opt-in to the new mapping driver mode that was added in Doctrine ORM 2.14. See https://github.com/doctrine/orm/pull/6728. // Default: false + * second_level_cache?: array{ + * region_cache_driver?: string|array{ + * type?: scalar|Param|null, // Default: null + * id?: scalar|Param|null, + * pool?: scalar|Param|null, * }, - * connection?: scalar|Param|null, - * class_metadata_factory_name?: scalar|Param|null, // Default: "Doctrine\\ORM\\Mapping\\ClassMetadataFactory" - * default_repository_class?: scalar|Param|null, // Default: "Doctrine\\ORM\\EntityRepository" - * auto_mapping?: scalar|Param|null, // Default: false - * naming_strategy?: scalar|Param|null, // Default: "doctrine.orm.naming_strategy.default" - * quote_strategy?: scalar|Param|null, // Default: "doctrine.orm.quote_strategy.default" - * typed_field_mapper?: scalar|Param|null, // Default: "doctrine.orm.typed_field_mapper.default" - * entity_listener_resolver?: scalar|Param|null, // Default: null - * fetch_mode_subselect_batch_size?: scalar|Param|null, - * repository_factory?: scalar|Param|null, // Default: "doctrine.orm.container_repository_factory" - * schema_ignore_classes?: list, - * report_fields_where_declared?: bool|Param, // Set to "true" to opt-in to the new mapping driver mode that was added in Doctrine ORM 2.16 and will be mandatory in ORM 3.0. See https://github.com/doctrine/orm/pull/10455. // Default: true - * validate_xml_mapping?: bool|Param, // Set to "true" to opt-in to the new mapping driver mode that was added in Doctrine ORM 2.14. See https://github.com/doctrine/orm/pull/6728. // Default: false - * second_level_cache?: array{ - * region_cache_driver?: string|array{ + * region_lock_lifetime?: scalar|Param|null, // Default: 60 + * log_enabled?: bool|Param, // Default: true + * region_lifetime?: scalar|Param|null, // Default: 3600 + * enabled?: bool|Param, // Default: true + * factory?: scalar|Param|null, + * regions?: array, - * loggers?: array, - * }, - * hydrators?: array, - * mappings?: array, - * dql?: array{ - * string_functions?: array, - * numeric_functions?: array, - * datetime_functions?: array, - * }, - * filters?: array, - * }>, - * identity_generation_preferences?: array, + * lock_path?: scalar|Param|null, // Default: "%kernel.cache_dir%/doctrine/orm/slc/filelock" + * lock_lifetime?: scalar|Param|null, // Default: 60 + * type?: scalar|Param|null, // Default: "default" + * lifetime?: scalar|Param|null, // Default: 0 + * service?: scalar|Param|null, + * name?: scalar|Param|null, + * }>, + * loggers?: array, + * }, + * hydrators?: array, + * mappings?: array, + * dql?: array{ + * string_functions?: array, + * numeric_functions?: array, + * datetime_functions?: array, + * }, + * filters?: array, + * }>, + * identity_generation_preferences?: array, + * }>, * resolve_target_entities?: array, * }, * } @@ -957,391 +957,391 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * allow_if_equal_granted_denied?: bool|Param, // Default: true * }, * password_hashers?: array, - * hash_algorithm?: scalar|Param|null, // Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms. // Default: "sha512" - * key_length?: scalar|Param|null, // Default: 40 - * ignore_case?: bool|Param, // Default: false - * encode_as_base64?: bool|Param, // Default: true - * iterations?: scalar|Param|null, // Default: 5000 - * cost?: int|Param, // Default: null - * memory_cost?: scalar|Param|null, // Default: null - * time_cost?: scalar|Param|null, // Default: null - * id?: scalar|Param|null, - * }>, + * algorithm?: scalar|Param|null, + * migrate_from?: string|list, + * hash_algorithm?: scalar|Param|null, // Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms. // Default: "sha512" + * key_length?: scalar|Param|null, // Default: 40 + * ignore_case?: bool|Param, // Default: false + * encode_as_base64?: bool|Param, // Default: true + * iterations?: scalar|Param|null, // Default: 5000 + * cost?: int|Param, // Default: null + * memory_cost?: scalar|Param|null, // Default: null + * time_cost?: scalar|Param|null, // Default: null + * id?: scalar|Param|null, + * }>, * providers?: array, - * }, - * entity?: array{ - * class?: scalar|Param|null, // The full entity class name of your user class. - * property?: scalar|Param|null, // Default: null - * manager_name?: scalar|Param|null, // Default: null - * }, - * memory?: array{ - * users?: array, - * }>, - * }, - * ldap?: array{ - * service?: scalar|Param|null, - * base_dn?: scalar|Param|null, - * search_dn?: scalar|Param|null, // Default: null - * search_password?: scalar|Param|null, // Default: null - * extra_fields?: list, - * default_roles?: string|list, - * role_fetcher?: scalar|Param|null, // Default: null - * uid_key?: scalar|Param|null, // Default: "sAMAccountName" - * filter?: scalar|Param|null, // Default: "({uid_key}={user_identifier})" - * password_attribute?: scalar|Param|null, // Default: null - * }, - * saml?: array{ - * user_class?: scalar|Param|null, - * default_roles?: list, - * }, - * }>, + * id?: scalar|Param|null, + * chain?: array{ + * providers?: string|list, + * }, + * entity?: array{ + * class?: scalar|Param|null, // The full entity class name of your user class. + * property?: scalar|Param|null, // Default: null + * manager_name?: scalar|Param|null, // Default: null + * }, + * memory?: array{ + * users?: array, + * }>, + * }, + * ldap?: array{ + * service?: scalar|Param|null, + * base_dn?: scalar|Param|null, + * search_dn?: scalar|Param|null, // Default: null + * search_password?: scalar|Param|null, // Default: null + * extra_fields?: list, + * default_roles?: string|list, + * role_fetcher?: scalar|Param|null, // Default: null + * uid_key?: scalar|Param|null, // Default: "sAMAccountName" + * filter?: scalar|Param|null, // Default: "({uid_key}={user_identifier})" + * password_attribute?: scalar|Param|null, // Default: null + * }, + * saml?: array{ + * user_class?: scalar|Param|null, + * default_roles?: list, + * }, + * }>, * firewalls?: array, - * security?: bool|Param, // Default: true - * user_checker?: scalar|Param|null, // The UserChecker to use when authenticating users in this firewall. // Default: "security.user_checker" - * request_matcher?: scalar|Param|null, - * access_denied_url?: scalar|Param|null, - * access_denied_handler?: scalar|Param|null, - * entry_point?: scalar|Param|null, // An enabled authenticator name or a service id that implements "Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface". - * provider?: scalar|Param|null, - * stateless?: bool|Param, // Default: false - * lazy?: bool|Param, // Default: false - * context?: scalar|Param|null, - * logout?: array{ - * enable_csrf?: bool|Param|null, // Default: null - * csrf_token_id?: scalar|Param|null, // Default: "logout" - * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" - * csrf_token_manager?: scalar|Param|null, - * path?: scalar|Param|null, // Default: "/logout" - * target?: scalar|Param|null, // Default: "/" - * invalidate_session?: bool|Param, // Default: true - * clear_site_data?: string|list<"*"|"cache"|"cookies"|"storage"|"executionContexts"|Param>, - * delete_cookies?: string|array, - * }, - * switch_user?: array{ - * provider?: scalar|Param|null, - * parameter?: scalar|Param|null, // Default: "_switch_user" - * role?: scalar|Param|null, // Default: "ROLE_ALLOWED_TO_SWITCH" - * target_route?: scalar|Param|null, // Default: null - * }, - * required_badges?: list, - * custom_authenticators?: list, - * login_throttling?: array{ - * limiter?: scalar|Param|null, // A service id implementing "Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface". - * max_attempts?: int|Param, // Default: 5 - * interval?: scalar|Param|null, // Default: "1 minute" - * lock_factory?: scalar|Param|null, // The service ID of the lock factory used by the login rate limiter (or null to disable locking). // Default: null - * cache_pool?: string|Param, // The cache pool to use for storing the limiter state // Default: "cache.rate_limiter" - * storage_service?: string|Param, // The service ID of a custom storage implementation, this precedes any configured "cache_pool" // Default: null - * }, - * two_factor?: array{ - * check_path?: scalar|Param|null, // Default: "/2fa_check" - * post_only?: bool|Param, // Default: true - * auth_form_path?: scalar|Param|null, // Default: "/2fa" - * always_use_default_target_path?: bool|Param, // Default: false - * default_target_path?: scalar|Param|null, // Default: "/" - * success_handler?: scalar|Param|null, // Default: null - * failure_handler?: scalar|Param|null, // Default: null - * authentication_required_handler?: scalar|Param|null, // Default: null - * auth_code_parameter_name?: scalar|Param|null, // Default: "_auth_code" - * trusted_parameter_name?: scalar|Param|null, // Default: "_trusted" - * remember_me_sets_trusted?: scalar|Param|null, // Default: false - * multi_factor?: bool|Param, // Default: false - * prepare_on_login?: bool|Param, // Default: false - * prepare_on_access_denied?: bool|Param, // Default: false - * enable_csrf?: scalar|Param|null, // Default: false - * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" - * csrf_token_id?: scalar|Param|null, // Default: "two_factor" - * csrf_header?: scalar|Param|null, // Default: null - * csrf_token_manager?: scalar|Param|null, // Default: "scheb_two_factor.csrf_token_manager" - * provider?: scalar|Param|null, // Default: null - * }, - * webauthn?: array{ - * user_provider?: scalar|Param|null, // Default: null - * options_storage?: scalar|Param|null, // Deprecated: The child node "options_storage" at path "security.firewalls..webauthn.options_storage" is deprecated. Please use the root option "options_storage" instead. // Default: null - * success_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultSuccessHandler" - * failure_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultFailureHandler" - * secured_rp_ids?: array, - * authentication?: bool|array{ - * enabled?: bool|Param, // Default: true - * profile?: scalar|Param|null, // Default: "default" - * options_builder?: scalar|Param|null, // Default: null - * routes?: array{ - * host?: scalar|Param|null, // Default: null - * options_method?: scalar|Param|null, // Default: "POST" - * options_path?: scalar|Param|null, // Default: "/login/options" - * result_method?: scalar|Param|null, // Default: "POST" - * result_path?: scalar|Param|null, // Default: "/login" - * }, - * options_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultRequestOptionsHandler" - * }, - * registration?: bool|array{ - * enabled?: bool|Param, // Default: false - * hide_existing_credentials?: bool|Param, // Default: true - * profile?: scalar|Param|null, // Default: "default" - * options_builder?: scalar|Param|null, // Default: null - * routes?: array{ - * host?: scalar|Param|null, // Default: null - * options_method?: scalar|Param|null, // Default: "POST" - * options_path?: scalar|Param|null, // Default: "/register/options" - * result_method?: scalar|Param|null, // Default: "POST" - * result_path?: scalar|Param|null, // Default: "/register" - * }, - * options_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultCreationOptionsHandler" - * }, - * }, - * x509?: array{ - * provider?: scalar|Param|null, - * user?: scalar|Param|null, // Default: "SSL_CLIENT_S_DN_Email" - * credentials?: scalar|Param|null, // Default: "SSL_CLIENT_S_DN" - * user_identifier?: scalar|Param|null, // Default: "emailAddress" - * }, - * remote_user?: array{ - * provider?: scalar|Param|null, - * user?: scalar|Param|null, // Default: "REMOTE_USER" - * }, - * saml?: array{ - * provider?: scalar|Param|null, - * remember_me?: bool|Param, // Default: true - * success_handler?: scalar|Param|null, // Default: "Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authentication\\SamlAuthenticationSuccessHandler" - * failure_handler?: scalar|Param|null, - * check_path?: scalar|Param|null, // Default: "/login_check" - * use_forward?: bool|Param, // Default: false - * login_path?: scalar|Param|null, // Default: "/login" - * identifier_attribute?: scalar|Param|null, // Default: null - * use_attribute_friendly_name?: bool|Param, // Default: false - * user_factory?: scalar|Param|null, // Default: null - * token_factory?: scalar|Param|null, // Default: null - * persist_user?: bool|Param, // Default: false - * always_use_default_target_path?: bool|Param, // Default: false - * default_target_path?: scalar|Param|null, // Default: "/" - * target_path_parameter?: scalar|Param|null, // Default: "_target_path" - * use_referer?: bool|Param, // Default: false - * failure_path?: scalar|Param|null, // Default: null - * failure_forward?: bool|Param, // Default: false - * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" - * }, - * login_link?: array{ - * check_route?: scalar|Param|null, // Route that will validate the login link - e.g. "app_login_link_verify". - * check_post_only?: scalar|Param|null, // If true, only HTTP POST requests to "check_route" will be handled by the authenticator. // Default: false - * signature_properties?: list, - * lifetime?: int|Param, // The lifetime of the login link in seconds. // Default: 600 - * max_uses?: int|Param, // Max number of times a login link can be used - null means unlimited within lifetime. // Default: null - * used_link_cache?: scalar|Param|null, // Cache service id used to expired links of max_uses is set. - * success_handler?: scalar|Param|null, // A service id that implements Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface. - * failure_handler?: scalar|Param|null, // A service id that implements Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface. - * provider?: scalar|Param|null, // The user provider to load users from. - * secret?: scalar|Param|null, // Default: "%kernel.secret%" - * always_use_default_target_path?: bool|Param, // Default: false - * default_target_path?: scalar|Param|null, // Default: "/" - * login_path?: scalar|Param|null, // Default: "/login" - * target_path_parameter?: scalar|Param|null, // Default: "_target_path" - * use_referer?: bool|Param, // Default: false - * failure_path?: scalar|Param|null, // Default: null - * failure_forward?: bool|Param, // Default: false - * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" - * }, - * form_login?: array{ - * provider?: scalar|Param|null, - * remember_me?: bool|Param, // Default: true - * success_handler?: scalar|Param|null, - * failure_handler?: scalar|Param|null, - * check_path?: scalar|Param|null, // Default: "/login_check" - * use_forward?: bool|Param, // Default: false - * login_path?: scalar|Param|null, // Default: "/login" - * username_parameter?: scalar|Param|null, // Default: "_username" - * password_parameter?: scalar|Param|null, // Default: "_password" - * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" - * csrf_token_id?: scalar|Param|null, // Default: "authenticate" - * enable_csrf?: bool|Param, // Default: false - * post_only?: bool|Param, // Default: true - * form_only?: bool|Param, // Default: false - * always_use_default_target_path?: bool|Param, // Default: false - * default_target_path?: scalar|Param|null, // Default: "/" - * target_path_parameter?: scalar|Param|null, // Default: "_target_path" - * use_referer?: bool|Param, // Default: false - * failure_path?: scalar|Param|null, // Default: null - * failure_forward?: bool|Param, // Default: false - * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" - * }, - * form_login_ldap?: array{ - * provider?: scalar|Param|null, - * remember_me?: bool|Param, // Default: true - * success_handler?: scalar|Param|null, - * failure_handler?: scalar|Param|null, - * check_path?: scalar|Param|null, // Default: "/login_check" - * use_forward?: bool|Param, // Default: false - * login_path?: scalar|Param|null, // Default: "/login" - * username_parameter?: scalar|Param|null, // Default: "_username" - * password_parameter?: scalar|Param|null, // Default: "_password" - * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" - * csrf_token_id?: scalar|Param|null, // Default: "authenticate" - * enable_csrf?: bool|Param, // Default: false - * post_only?: bool|Param, // Default: true - * form_only?: bool|Param, // Default: false - * always_use_default_target_path?: bool|Param, // Default: false - * default_target_path?: scalar|Param|null, // Default: "/" - * target_path_parameter?: scalar|Param|null, // Default: "_target_path" - * use_referer?: bool|Param, // Default: false - * failure_path?: scalar|Param|null, // Default: null - * failure_forward?: bool|Param, // Default: false - * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" - * service?: scalar|Param|null, // Default: "ldap" - * dn_string?: scalar|Param|null, // Default: "{user_identifier}" - * query_string?: scalar|Param|null, - * search_dn?: scalar|Param|null, // Default: "" - * search_password?: scalar|Param|null, // Default: "" - * }, - * json_login?: array{ - * provider?: scalar|Param|null, - * remember_me?: bool|Param, // Default: true - * success_handler?: scalar|Param|null, - * failure_handler?: scalar|Param|null, - * check_path?: scalar|Param|null, // Default: "/login_check" - * use_forward?: bool|Param, // Default: false - * login_path?: scalar|Param|null, // Default: "/login" - * username_path?: scalar|Param|null, // Default: "username" - * password_path?: scalar|Param|null, // Default: "password" - * }, - * json_login_ldap?: array{ - * provider?: scalar|Param|null, - * remember_me?: bool|Param, // Default: true - * success_handler?: scalar|Param|null, - * failure_handler?: scalar|Param|null, - * check_path?: scalar|Param|null, // Default: "/login_check" - * use_forward?: bool|Param, // Default: false - * login_path?: scalar|Param|null, // Default: "/login" - * username_path?: scalar|Param|null, // Default: "username" - * password_path?: scalar|Param|null, // Default: "password" - * service?: scalar|Param|null, // Default: "ldap" - * dn_string?: scalar|Param|null, // Default: "{user_identifier}" - * query_string?: scalar|Param|null, - * search_dn?: scalar|Param|null, // Default: "" - * search_password?: scalar|Param|null, // Default: "" - * }, - * access_token?: array{ - * provider?: scalar|Param|null, - * remember_me?: bool|Param, // Default: true - * success_handler?: scalar|Param|null, - * failure_handler?: scalar|Param|null, - * realm?: scalar|Param|null, // Default: null - * token_extractors?: string|list, - * token_handler?: string|array{ - * id?: scalar|Param|null, - * oidc_user_info?: string|array{ - * base_uri?: scalar|Param|null, // Base URI of the userinfo endpoint on the OIDC server, or the OIDC server URI to use the discovery (require "discovery" to be configured). - * discovery?: array{ // Enable the OIDC discovery. - * cache?: array{ - * id?: scalar|Param|null, // Cache service id to use to cache the OIDC discovery configuration. - * }, - * }, - * claim?: scalar|Param|null, // Claim which contains the user identifier (e.g. sub, email, etc.). // Default: "sub" - * client?: scalar|Param|null, // HttpClient service id to use to call the OIDC server. - * }, - * oidc?: array{ - * discovery?: array{ // Enable the OIDC discovery. - * base_uri?: string|list, - * cache?: array{ - * id?: scalar|Param|null, // Cache service id to use to cache the OIDC discovery configuration. - * }, - * }, - * claim?: scalar|Param|null, // Claim which contains the user identifier (e.g.: sub, email..). // Default: "sub" - * audience?: scalar|Param|null, // Audience set in the token, for validation purpose. - * issuers?: list, - * algorithm?: array, - * algorithms?: list, - * key?: scalar|Param|null, // Deprecated: The "key" option is deprecated and will be removed in 8.0. Use the "keyset" option instead. // JSON-encoded JWK used to sign the token (must contain a "kty" key). - * keyset?: scalar|Param|null, // JSON-encoded JWKSet used to sign the token (must contain a list of valid public keys). - * encryption?: bool|array{ - * enabled?: bool|Param, // Default: false - * enforce?: bool|Param, // When enabled, the token shall be encrypted. // Default: false - * algorithms?: list, - * keyset?: scalar|Param|null, // JSON-encoded JWKSet used to decrypt the token (must contain a list of valid private keys). - * }, - * }, - * cas?: array{ - * validation_url?: scalar|Param|null, // CAS server validation URL - * prefix?: scalar|Param|null, // CAS prefix // Default: "cas" - * http_client?: scalar|Param|null, // HTTP Client service // Default: null - * }, - * oauth2?: scalar|Param|null, - * }, - * }, - * http_basic?: array{ - * provider?: scalar|Param|null, - * realm?: scalar|Param|null, // Default: "Secured Area" - * }, - * http_basic_ldap?: array{ - * provider?: scalar|Param|null, - * realm?: scalar|Param|null, // Default: "Secured Area" - * service?: scalar|Param|null, // Default: "ldap" - * dn_string?: scalar|Param|null, // Default: "{user_identifier}" - * query_string?: scalar|Param|null, - * search_dn?: scalar|Param|null, // Default: "" - * search_password?: scalar|Param|null, // Default: "" - * }, - * remember_me?: array{ - * secret?: scalar|Param|null, // Default: "%kernel.secret%" - * service?: scalar|Param|null, - * user_providers?: string|list, - * catch_exceptions?: bool|Param, // Default: true - * signature_properties?: list, - * token_provider?: string|array{ - * service?: scalar|Param|null, // The service ID of a custom remember-me token provider. - * doctrine?: bool|array{ - * enabled?: bool|Param, // Default: false - * connection?: scalar|Param|null, // Default: null - * }, - * }, - * token_verifier?: scalar|Param|null, // The service ID of a custom rememberme token verifier. - * name?: scalar|Param|null, // Default: "REMEMBERME" - * lifetime?: int|Param, // Default: 31536000 - * path?: scalar|Param|null, // Default: "/" + * pattern?: scalar|Param|null, + * host?: scalar|Param|null, + * methods?: string|list, + * security?: bool|Param, // Default: true + * user_checker?: scalar|Param|null, // The UserChecker to use when authenticating users in this firewall. // Default: "security.user_checker" + * request_matcher?: scalar|Param|null, + * access_denied_url?: scalar|Param|null, + * access_denied_handler?: scalar|Param|null, + * entry_point?: scalar|Param|null, // An enabled authenticator name or a service id that implements "Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface". + * provider?: scalar|Param|null, + * stateless?: bool|Param, // Default: false + * lazy?: bool|Param, // Default: false + * context?: scalar|Param|null, + * logout?: array{ + * enable_csrf?: bool|Param|null, // Default: null + * csrf_token_id?: scalar|Param|null, // Default: "logout" + * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" + * csrf_token_manager?: scalar|Param|null, + * path?: scalar|Param|null, // Default: "/logout" + * target?: scalar|Param|null, // Default: "/" + * invalidate_session?: bool|Param, // Default: true + * clear_site_data?: string|list<"*"|"cache"|"cookies"|"storage"|"executionContexts"|Param>, + * delete_cookies?: string|array, + * }, + * switch_user?: array{ + * provider?: scalar|Param|null, + * parameter?: scalar|Param|null, // Default: "_switch_user" + * role?: scalar|Param|null, // Default: "ROLE_ALLOWED_TO_SWITCH" + * target_route?: scalar|Param|null, // Default: null + * }, + * required_badges?: list, + * custom_authenticators?: list, + * login_throttling?: array{ + * limiter?: scalar|Param|null, // A service id implementing "Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface". + * max_attempts?: int|Param, // Default: 5 + * interval?: scalar|Param|null, // Default: "1 minute" + * lock_factory?: scalar|Param|null, // The service ID of the lock factory used by the login rate limiter (or null to disable locking). // Default: null + * cache_pool?: string|Param, // The cache pool to use for storing the limiter state // Default: "cache.rate_limiter" + * storage_service?: string|Param, // The service ID of a custom storage implementation, this precedes any configured "cache_pool" // Default: null + * }, + * two_factor?: array{ + * check_path?: scalar|Param|null, // Default: "/2fa_check" + * post_only?: bool|Param, // Default: true + * auth_form_path?: scalar|Param|null, // Default: "/2fa" + * always_use_default_target_path?: bool|Param, // Default: false + * default_target_path?: scalar|Param|null, // Default: "/" + * success_handler?: scalar|Param|null, // Default: null + * failure_handler?: scalar|Param|null, // Default: null + * authentication_required_handler?: scalar|Param|null, // Default: null + * auth_code_parameter_name?: scalar|Param|null, // Default: "_auth_code" + * trusted_parameter_name?: scalar|Param|null, // Default: "_trusted" + * remember_me_sets_trusted?: scalar|Param|null, // Default: false + * multi_factor?: bool|Param, // Default: false + * prepare_on_login?: bool|Param, // Default: false + * prepare_on_access_denied?: bool|Param, // Default: false + * enable_csrf?: scalar|Param|null, // Default: false + * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" + * csrf_token_id?: scalar|Param|null, // Default: "two_factor" + * csrf_header?: scalar|Param|null, // Default: null + * csrf_token_manager?: scalar|Param|null, // Default: "scheb_two_factor.csrf_token_manager" + * provider?: scalar|Param|null, // Default: null + * }, + * webauthn?: array{ + * user_provider?: scalar|Param|null, // Default: null + * options_storage?: scalar|Param|null, // Deprecated: The child node "options_storage" at path "security.firewalls..webauthn.options_storage" is deprecated. Please use the root option "options_storage" instead. // Default: null + * success_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultSuccessHandler" + * failure_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultFailureHandler" + * secured_rp_ids?: array, + * authentication?: bool|array{ + * enabled?: bool|Param, // Default: true + * profile?: scalar|Param|null, // Default: "default" + * options_builder?: scalar|Param|null, // Default: null + * routes?: array{ + * host?: scalar|Param|null, // Default: null + * options_method?: scalar|Param|null, // Default: "POST" + * options_path?: scalar|Param|null, // Default: "/login/options" + * result_method?: scalar|Param|null, // Default: "POST" + * result_path?: scalar|Param|null, // Default: "/login" + * }, + * options_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultRequestOptionsHandler" * }, - * }>, + * registration?: bool|array{ + * enabled?: bool|Param, // Default: false + * hide_existing_credentials?: bool|Param, // Default: true + * profile?: scalar|Param|null, // Default: "default" + * options_builder?: scalar|Param|null, // Default: null + * routes?: array{ + * host?: scalar|Param|null, // Default: null + * options_method?: scalar|Param|null, // Default: "POST" + * options_path?: scalar|Param|null, // Default: "/register/options" + * result_method?: scalar|Param|null, // Default: "POST" + * result_path?: scalar|Param|null, // Default: "/register" + * }, + * options_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultCreationOptionsHandler" + * }, + * }, + * x509?: array{ + * provider?: scalar|Param|null, + * user?: scalar|Param|null, // Default: "SSL_CLIENT_S_DN_Email" + * credentials?: scalar|Param|null, // Default: "SSL_CLIENT_S_DN" + * user_identifier?: scalar|Param|null, // Default: "emailAddress" + * }, + * remote_user?: array{ + * provider?: scalar|Param|null, + * user?: scalar|Param|null, // Default: "REMOTE_USER" + * }, + * saml?: array{ + * provider?: scalar|Param|null, + * remember_me?: bool|Param, // Default: true + * success_handler?: scalar|Param|null, // Default: "Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authentication\\SamlAuthenticationSuccessHandler" + * failure_handler?: scalar|Param|null, + * check_path?: scalar|Param|null, // Default: "/login_check" + * use_forward?: bool|Param, // Default: false + * login_path?: scalar|Param|null, // Default: "/login" + * identifier_attribute?: scalar|Param|null, // Default: null + * use_attribute_friendly_name?: bool|Param, // Default: false + * user_factory?: scalar|Param|null, // Default: null + * token_factory?: scalar|Param|null, // Default: null + * persist_user?: bool|Param, // Default: false + * always_use_default_target_path?: bool|Param, // Default: false + * default_target_path?: scalar|Param|null, // Default: "/" + * target_path_parameter?: scalar|Param|null, // Default: "_target_path" + * use_referer?: bool|Param, // Default: false + * failure_path?: scalar|Param|null, // Default: null + * failure_forward?: bool|Param, // Default: false + * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" + * }, + * login_link?: array{ + * check_route?: scalar|Param|null, // Route that will validate the login link - e.g. "app_login_link_verify". + * check_post_only?: scalar|Param|null, // If true, only HTTP POST requests to "check_route" will be handled by the authenticator. // Default: false + * signature_properties?: list, + * lifetime?: int|Param, // The lifetime of the login link in seconds. // Default: 600 + * max_uses?: int|Param, // Max number of times a login link can be used - null means unlimited within lifetime. // Default: null + * used_link_cache?: scalar|Param|null, // Cache service id used to expired links of max_uses is set. + * success_handler?: scalar|Param|null, // A service id that implements Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface. + * failure_handler?: scalar|Param|null, // A service id that implements Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface. + * provider?: scalar|Param|null, // The user provider to load users from. + * secret?: scalar|Param|null, // Default: "%kernel.secret%" + * always_use_default_target_path?: bool|Param, // Default: false + * default_target_path?: scalar|Param|null, // Default: "/" + * login_path?: scalar|Param|null, // Default: "/login" + * target_path_parameter?: scalar|Param|null, // Default: "_target_path" + * use_referer?: bool|Param, // Default: false + * failure_path?: scalar|Param|null, // Default: null + * failure_forward?: bool|Param, // Default: false + * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" + * }, + * form_login?: array{ + * provider?: scalar|Param|null, + * remember_me?: bool|Param, // Default: true + * success_handler?: scalar|Param|null, + * failure_handler?: scalar|Param|null, + * check_path?: scalar|Param|null, // Default: "/login_check" + * use_forward?: bool|Param, // Default: false + * login_path?: scalar|Param|null, // Default: "/login" + * username_parameter?: scalar|Param|null, // Default: "_username" + * password_parameter?: scalar|Param|null, // Default: "_password" + * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" + * csrf_token_id?: scalar|Param|null, // Default: "authenticate" + * enable_csrf?: bool|Param, // Default: false + * post_only?: bool|Param, // Default: true + * form_only?: bool|Param, // Default: false + * always_use_default_target_path?: bool|Param, // Default: false + * default_target_path?: scalar|Param|null, // Default: "/" + * target_path_parameter?: scalar|Param|null, // Default: "_target_path" + * use_referer?: bool|Param, // Default: false + * failure_path?: scalar|Param|null, // Default: null + * failure_forward?: bool|Param, // Default: false + * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" + * }, + * form_login_ldap?: array{ + * provider?: scalar|Param|null, + * remember_me?: bool|Param, // Default: true + * success_handler?: scalar|Param|null, + * failure_handler?: scalar|Param|null, + * check_path?: scalar|Param|null, // Default: "/login_check" + * use_forward?: bool|Param, // Default: false + * login_path?: scalar|Param|null, // Default: "/login" + * username_parameter?: scalar|Param|null, // Default: "_username" + * password_parameter?: scalar|Param|null, // Default: "_password" + * csrf_parameter?: scalar|Param|null, // Default: "_csrf_token" + * csrf_token_id?: scalar|Param|null, // Default: "authenticate" + * enable_csrf?: bool|Param, // Default: false + * post_only?: bool|Param, // Default: true + * form_only?: bool|Param, // Default: false + * always_use_default_target_path?: bool|Param, // Default: false + * default_target_path?: scalar|Param|null, // Default: "/" + * target_path_parameter?: scalar|Param|null, // Default: "_target_path" + * use_referer?: bool|Param, // Default: false + * failure_path?: scalar|Param|null, // Default: null + * failure_forward?: bool|Param, // Default: false + * failure_path_parameter?: scalar|Param|null, // Default: "_failure_path" + * service?: scalar|Param|null, // Default: "ldap" + * dn_string?: scalar|Param|null, // Default: "{user_identifier}" + * query_string?: scalar|Param|null, + * search_dn?: scalar|Param|null, // Default: "" + * search_password?: scalar|Param|null, // Default: "" + * }, + * json_login?: array{ + * provider?: scalar|Param|null, + * remember_me?: bool|Param, // Default: true + * success_handler?: scalar|Param|null, + * failure_handler?: scalar|Param|null, + * check_path?: scalar|Param|null, // Default: "/login_check" + * use_forward?: bool|Param, // Default: false + * login_path?: scalar|Param|null, // Default: "/login" + * username_path?: scalar|Param|null, // Default: "username" + * password_path?: scalar|Param|null, // Default: "password" + * }, + * json_login_ldap?: array{ + * provider?: scalar|Param|null, + * remember_me?: bool|Param, // Default: true + * success_handler?: scalar|Param|null, + * failure_handler?: scalar|Param|null, + * check_path?: scalar|Param|null, // Default: "/login_check" + * use_forward?: bool|Param, // Default: false + * login_path?: scalar|Param|null, // Default: "/login" + * username_path?: scalar|Param|null, // Default: "username" + * password_path?: scalar|Param|null, // Default: "password" + * service?: scalar|Param|null, // Default: "ldap" + * dn_string?: scalar|Param|null, // Default: "{user_identifier}" + * query_string?: scalar|Param|null, + * search_dn?: scalar|Param|null, // Default: "" + * search_password?: scalar|Param|null, // Default: "" + * }, + * access_token?: array{ + * provider?: scalar|Param|null, + * remember_me?: bool|Param, // Default: true + * success_handler?: scalar|Param|null, + * failure_handler?: scalar|Param|null, + * realm?: scalar|Param|null, // Default: null + * token_extractors?: string|list, + * token_handler?: string|array{ + * id?: scalar|Param|null, + * oidc_user_info?: string|array{ + * base_uri?: scalar|Param|null, // Base URI of the userinfo endpoint on the OIDC server, or the OIDC server URI to use the discovery (require "discovery" to be configured). + * discovery?: array{ // Enable the OIDC discovery. + * cache?: array{ + * id?: scalar|Param|null, // Cache service id to use to cache the OIDC discovery configuration. + * }, + * }, + * claim?: scalar|Param|null, // Claim which contains the user identifier (e.g. sub, email, etc.). // Default: "sub" + * client?: scalar|Param|null, // HttpClient service id to use to call the OIDC server. + * }, + * oidc?: array{ + * discovery?: array{ // Enable the OIDC discovery. + * base_uri?: string|list, + * cache?: array{ + * id?: scalar|Param|null, // Cache service id to use to cache the OIDC discovery configuration. + * }, + * }, + * claim?: scalar|Param|null, // Claim which contains the user identifier (e.g.: sub, email..). // Default: "sub" + * audience?: scalar|Param|null, // Audience set in the token, for validation purpose. + * issuers?: list, + * algorithm?: array, + * algorithms?: list, + * key?: scalar|Param|null, // Deprecated: The "key" option is deprecated and will be removed in 8.0. Use the "keyset" option instead. // JSON-encoded JWK used to sign the token (must contain a "kty" key). + * keyset?: scalar|Param|null, // JSON-encoded JWKSet used to sign the token (must contain a list of valid public keys). + * encryption?: bool|array{ + * enabled?: bool|Param, // Default: false + * enforce?: bool|Param, // When enabled, the token shall be encrypted. // Default: false + * algorithms?: list, + * keyset?: scalar|Param|null, // JSON-encoded JWKSet used to decrypt the token (must contain a list of valid private keys). + * }, + * }, + * cas?: array{ + * validation_url?: scalar|Param|null, // CAS server validation URL + * prefix?: scalar|Param|null, // CAS prefix // Default: "cas" + * http_client?: scalar|Param|null, // HTTP Client service // Default: null + * }, + * oauth2?: scalar|Param|null, + * }, + * }, + * http_basic?: array{ + * provider?: scalar|Param|null, + * realm?: scalar|Param|null, // Default: "Secured Area" + * }, + * http_basic_ldap?: array{ + * provider?: scalar|Param|null, + * realm?: scalar|Param|null, // Default: "Secured Area" + * service?: scalar|Param|null, // Default: "ldap" + * dn_string?: scalar|Param|null, // Default: "{user_identifier}" + * query_string?: scalar|Param|null, + * search_dn?: scalar|Param|null, // Default: "" + * search_password?: scalar|Param|null, // Default: "" + * }, + * remember_me?: array{ + * secret?: scalar|Param|null, // Default: "%kernel.secret%" + * service?: scalar|Param|null, + * user_providers?: string|list, + * catch_exceptions?: bool|Param, // Default: true + * signature_properties?: list, + * token_provider?: string|array{ + * service?: scalar|Param|null, // The service ID of a custom remember-me token provider. + * doctrine?: bool|array{ + * enabled?: bool|Param, // Default: false + * connection?: scalar|Param|null, // Default: null + * }, + * }, + * token_verifier?: scalar|Param|null, // The service ID of a custom rememberme token verifier. + * name?: scalar|Param|null, // Default: "REMEMBERME" + * lifetime?: int|Param, // Default: 31536000 + * path?: scalar|Param|null, // Default: "/" + * domain?: scalar|Param|null, // Default: null + * secure?: true|false|"auto"|Param, // Default: null + * httponly?: bool|Param, // Default: true + * samesite?: null|"lax"|"strict"|"none"|Param, // Default: "lax" + * always_remember_me?: bool|Param, // Default: false + * remember_me_parameter?: scalar|Param|null, // Default: "_remember_me" + * }, + * }>, * access_control?: list, - * attributes?: array, - * route?: scalar|Param|null, // Default: null - * methods?: string|list, - * allow_if?: scalar|Param|null, // Default: null - * roles?: string|list, - * }>, + * request_matcher?: scalar|Param|null, // Default: null + * requires_channel?: scalar|Param|null, // Default: null + * path?: scalar|Param|null, // Use the urldecoded format. // Default: null + * host?: scalar|Param|null, // Default: null + * port?: int|Param, // Default: null + * ips?: string|list, + * attributes?: array, + * route?: scalar|Param|null, // Default: null + * methods?: string|list, + * allow_if?: scalar|Param|null, // Default: null + * roles?: string|list, + * }>, * role_hierarchy?: array>, * } * @psalm-type TwigConfig = array{ * form_themes?: list, * globals?: array, + * id?: scalar|Param|null, + * type?: scalar|Param|null, + * value?: mixed, + * }>, * autoescape_service?: scalar|Param|null, // Default: null * autoescape_service_method?: scalar|Param|null, // Default: null * base_template_class?: scalar|Param|null, // Deprecated: The child node "base_template_class" at path "twig.base_template_class" is deprecated. @@ -1380,144 +1380,144 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * use_microseconds?: scalar|Param|null, // Default: true * channels?: list, * handlers?: array, - * }>, - * accepted_levels?: list, - * min_level?: scalar|Param|null, // Default: "DEBUG" - * max_level?: scalar|Param|null, // Default: "EMERGENCY" - * buffer_size?: scalar|Param|null, // Default: 0 - * flush_on_overflow?: bool|Param, // Default: false - * handler?: scalar|Param|null, - * url?: scalar|Param|null, - * exchange?: scalar|Param|null, - * exchange_name?: scalar|Param|null, // Default: "log" - * channel?: scalar|Param|null, // Default: null - * bot_name?: scalar|Param|null, // Default: "Monolog" - * use_attachment?: scalar|Param|null, // Default: true - * use_short_attachment?: scalar|Param|null, // Default: false - * include_extra?: scalar|Param|null, // Default: false - * icon_emoji?: scalar|Param|null, // Default: null - * webhook_url?: scalar|Param|null, - * exclude_fields?: list, - * token?: scalar|Param|null, - * region?: scalar|Param|null, - * source?: scalar|Param|null, - * use_ssl?: bool|Param, // Default: true - * user?: mixed, - * title?: scalar|Param|null, // Default: null - * host?: scalar|Param|null, // Default: null - * port?: scalar|Param|null, // Default: 514 - * config?: list, - * members?: list, - * connection_string?: scalar|Param|null, - * timeout?: scalar|Param|null, - * time?: scalar|Param|null, // Default: 60 - * deduplication_level?: scalar|Param|null, // Default: 400 - * store?: scalar|Param|null, // Default: null - * connection_timeout?: scalar|Param|null, - * persistent?: bool|Param, - * message_type?: scalar|Param|null, // Default: 0 - * parse_mode?: scalar|Param|null, // Default: null - * disable_webpage_preview?: bool|Param|null, // Default: null - * disable_notification?: bool|Param|null, // Default: null - * split_long_messages?: bool|Param, // Default: false - * delay_between_messages?: bool|Param, // Default: false - * topic?: int|Param, // Default: null - * factor?: int|Param, // Default: 1 - * tags?: string|list, - * console_formatter_options?: mixed, // Default: [] - * formatter?: scalar|Param|null, - * nested?: bool|Param, // Default: false - * publisher?: string|array{ - * id?: scalar|Param|null, - * hostname?: scalar|Param|null, - * port?: scalar|Param|null, // Default: 12201 - * chunk_size?: scalar|Param|null, // Default: 1420 - * encoder?: "json"|"compressed_json"|Param, - * }, - * mongodb?: string|array{ - * id?: scalar|Param|null, // ID of a MongoDB\Client service - * uri?: scalar|Param|null, - * username?: scalar|Param|null, - * password?: scalar|Param|null, - * database?: scalar|Param|null, // Default: "monolog" - * collection?: scalar|Param|null, // Default: "logs" - * }, - * elasticsearch?: string|array{ - * id?: scalar|Param|null, - * hosts?: list, - * host?: scalar|Param|null, - * port?: scalar|Param|null, // Default: 9200 - * transport?: scalar|Param|null, // Default: "Http" - * user?: scalar|Param|null, // Default: null - * password?: scalar|Param|null, // Default: null - * }, - * index?: scalar|Param|null, // Default: "monolog" - * document_type?: scalar|Param|null, // Default: "logs" - * ignore_error?: scalar|Param|null, // Default: false - * redis?: string|array{ - * id?: scalar|Param|null, - * host?: scalar|Param|null, - * password?: scalar|Param|null, // Default: null - * port?: scalar|Param|null, // Default: 6379 - * database?: scalar|Param|null, // Default: 0 - * key_name?: scalar|Param|null, // Default: "monolog_redis" - * }, - * predis?: string|array{ - * id?: scalar|Param|null, - * host?: scalar|Param|null, - * }, - * from_email?: scalar|Param|null, - * to_email?: string|list, - * subject?: scalar|Param|null, - * content_type?: scalar|Param|null, // Default: null - * headers?: list, - * mailer?: scalar|Param|null, // Default: null - * email_prototype?: string|array{ - * id?: scalar|Param|null, - * method?: scalar|Param|null, // Default: null - * }, - * verbosity_levels?: array{ - * VERBOSITY_QUIET?: scalar|Param|null, // Default: "ERROR" - * VERBOSITY_NORMAL?: scalar|Param|null, // Default: "WARNING" - * VERBOSITY_VERBOSE?: scalar|Param|null, // Default: "NOTICE" - * VERBOSITY_VERY_VERBOSE?: scalar|Param|null, // Default: "INFO" - * VERBOSITY_DEBUG?: scalar|Param|null, // Default: "DEBUG" - * }, - * channels?: string|array{ - * type?: scalar|Param|null, - * elements?: list, - * }, + * type?: scalar|Param|null, + * id?: scalar|Param|null, + * enabled?: bool|Param, // Default: true + * priority?: scalar|Param|null, // Default: 0 + * level?: scalar|Param|null, // Default: "DEBUG" + * bubble?: bool|Param, // Default: true + * interactive_only?: bool|Param, // Default: false + * app_name?: scalar|Param|null, // Default: null + * include_stacktraces?: bool|Param, // Default: false + * process_psr_3_messages?: array{ + * enabled?: bool|Param|null, // Default: null + * date_format?: scalar|Param|null, + * remove_used_context_fields?: bool|Param, + * }, + * path?: scalar|Param|null, // Default: "%kernel.logs_dir%/%kernel.environment%.log" + * file_permission?: scalar|Param|null, // Default: null + * use_locking?: bool|Param, // Default: false + * filename_format?: scalar|Param|null, // Default: "{filename}-{date}" + * date_format?: scalar|Param|null, // Default: "Y-m-d" + * ident?: scalar|Param|null, // Default: false + * logopts?: scalar|Param|null, // Default: 1 + * facility?: scalar|Param|null, // Default: "user" + * max_files?: scalar|Param|null, // Default: 0 + * action_level?: scalar|Param|null, // Default: "WARNING" + * activation_strategy?: scalar|Param|null, // Default: null + * stop_buffering?: bool|Param, // Default: true + * passthru_level?: scalar|Param|null, // Default: null + * excluded_http_codes?: list, * }>, + * accepted_levels?: list, + * min_level?: scalar|Param|null, // Default: "DEBUG" + * max_level?: scalar|Param|null, // Default: "EMERGENCY" + * buffer_size?: scalar|Param|null, // Default: 0 + * flush_on_overflow?: bool|Param, // Default: false + * handler?: scalar|Param|null, + * url?: scalar|Param|null, + * exchange?: scalar|Param|null, + * exchange_name?: scalar|Param|null, // Default: "log" + * channel?: scalar|Param|null, // Default: null + * bot_name?: scalar|Param|null, // Default: "Monolog" + * use_attachment?: scalar|Param|null, // Default: true + * use_short_attachment?: scalar|Param|null, // Default: false + * include_extra?: scalar|Param|null, // Default: false + * icon_emoji?: scalar|Param|null, // Default: null + * webhook_url?: scalar|Param|null, + * exclude_fields?: list, + * token?: scalar|Param|null, + * region?: scalar|Param|null, + * source?: scalar|Param|null, + * use_ssl?: bool|Param, // Default: true + * user?: mixed, + * title?: scalar|Param|null, // Default: null + * host?: scalar|Param|null, // Default: null + * port?: scalar|Param|null, // Default: 514 + * config?: list, + * members?: list, + * connection_string?: scalar|Param|null, + * timeout?: scalar|Param|null, + * time?: scalar|Param|null, // Default: 60 + * deduplication_level?: scalar|Param|null, // Default: 400 + * store?: scalar|Param|null, // Default: null + * connection_timeout?: scalar|Param|null, + * persistent?: bool|Param, + * message_type?: scalar|Param|null, // Default: 0 + * parse_mode?: scalar|Param|null, // Default: null + * disable_webpage_preview?: bool|Param|null, // Default: null + * disable_notification?: bool|Param|null, // Default: null + * split_long_messages?: bool|Param, // Default: false + * delay_between_messages?: bool|Param, // Default: false + * topic?: int|Param, // Default: null + * factor?: int|Param, // Default: 1 + * tags?: string|list, + * console_formatter_options?: mixed, // Default: [] + * formatter?: scalar|Param|null, + * nested?: bool|Param, // Default: false + * publisher?: string|array{ + * id?: scalar|Param|null, + * hostname?: scalar|Param|null, + * port?: scalar|Param|null, // Default: 12201 + * chunk_size?: scalar|Param|null, // Default: 1420 + * encoder?: "json"|"compressed_json"|Param, + * }, + * mongodb?: string|array{ + * id?: scalar|Param|null, // ID of a MongoDB\Client service + * uri?: scalar|Param|null, + * username?: scalar|Param|null, + * password?: scalar|Param|null, + * database?: scalar|Param|null, // Default: "monolog" + * collection?: scalar|Param|null, // Default: "logs" + * }, + * elasticsearch?: string|array{ + * id?: scalar|Param|null, + * hosts?: list, + * host?: scalar|Param|null, + * port?: scalar|Param|null, // Default: 9200 + * transport?: scalar|Param|null, // Default: "Http" + * user?: scalar|Param|null, // Default: null + * password?: scalar|Param|null, // Default: null + * }, + * index?: scalar|Param|null, // Default: "monolog" + * document_type?: scalar|Param|null, // Default: "logs" + * ignore_error?: scalar|Param|null, // Default: false + * redis?: string|array{ + * id?: scalar|Param|null, + * host?: scalar|Param|null, + * password?: scalar|Param|null, // Default: null + * port?: scalar|Param|null, // Default: 6379 + * database?: scalar|Param|null, // Default: 0 + * key_name?: scalar|Param|null, // Default: "monolog_redis" + * }, + * predis?: string|array{ + * id?: scalar|Param|null, + * host?: scalar|Param|null, + * }, + * from_email?: scalar|Param|null, + * to_email?: string|list, + * subject?: scalar|Param|null, + * content_type?: scalar|Param|null, // Default: null + * headers?: list, + * mailer?: scalar|Param|null, // Default: null + * email_prototype?: string|array{ + * id?: scalar|Param|null, + * method?: scalar|Param|null, // Default: null + * }, + * verbosity_levels?: array{ + * VERBOSITY_QUIET?: scalar|Param|null, // Default: "ERROR" + * VERBOSITY_NORMAL?: scalar|Param|null, // Default: "WARNING" + * VERBOSITY_VERBOSE?: scalar|Param|null, // Default: "NOTICE" + * VERBOSITY_VERY_VERBOSE?: scalar|Param|null, // Default: "INFO" + * VERBOSITY_DEBUG?: scalar|Param|null, // Default: "DEBUG" + * }, + * channels?: string|array{ + * type?: scalar|Param|null, + * elements?: list, + * }, + * }>, * } * @psalm-type DebugConfig = array{ * max_items?: int|Param, // Max number of displayed items past the first level, -1 means no limit. // Default: 2500 @@ -1557,52 +1557,52 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * } * @psalm-type LiipImagineConfig = array{ * resolvers?: array, - * get_options?: array, - * put_options?: array, - * proxies?: array, - * }, - * flysystem?: array{ - * filesystem_service?: scalar|Param|null, - * cache_prefix?: scalar|Param|null, // Default: "" - * root_url?: scalar|Param|null, - * visibility?: "public"|"private"|"noPredefinedVisibility"|Param, // Default: "public" - * }, - * }>, + * web_path?: array{ + * web_root?: scalar|Param|null, // Default: "%kernel.project_dir%/public" + * cache_prefix?: scalar|Param|null, // Default: "media/cache" + * }, + * aws_s3?: array{ + * bucket?: scalar|Param|null, + * cache?: scalar|Param|null, // Default: false + * use_psr_cache?: bool|Param, // Default: false + * acl?: scalar|Param|null, // Default: "public-read" + * cache_prefix?: scalar|Param|null, // Default: "" + * client_id?: scalar|Param|null, // Default: null + * client_config?: list, + * get_options?: array, + * put_options?: array, + * proxies?: array, + * }, + * flysystem?: array{ + * filesystem_service?: scalar|Param|null, + * cache_prefix?: scalar|Param|null, // Default: "" + * root_url?: scalar|Param|null, + * visibility?: "public"|"private"|"noPredefinedVisibility"|Param, // Default: "public" + * }, + * }>, * loaders?: array, + * allow_unresolvable_data_roots?: bool|Param, // Default: false + * bundle_resources?: array{ + * enabled?: bool|Param, // Default: false + * access_control_type?: "blacklist"|"whitelist"|Param, // Sets the access control method applied to bundle names in "access_control_list" into a blacklist or whitelist. // Default: "blacklist" + * access_control_list?: list, * }, - * filesystem?: array{ - * locator?: "filesystem"|"filesystem_insecure"|Param, // Using the "filesystem_insecure" locator is not recommended due to a less secure resolver mechanism, but is provided for those using heavily symlinked projects. // Default: "filesystem" - * data_root?: string|list, - * allow_unresolvable_data_roots?: bool|Param, // Default: false - * bundle_resources?: array{ - * enabled?: bool|Param, // Default: false - * access_control_type?: "blacklist"|"whitelist"|Param, // Sets the access control method applied to bundle names in "access_control_list" into a blacklist or whitelist. // Default: "blacklist" - * access_control_list?: list, - * }, - * }, - * flysystem?: array{ - * filesystem_service?: scalar|Param|null, - * }, - * asset_mapper?: array, - * chain?: array{ - * loaders?: list, - * }, - * }>, + * }, + * flysystem?: array{ + * filesystem_service?: scalar|Param|null, + * }, + * asset_mapper?: array, + * chain?: array{ + * loaders?: list, + * }, + * }>, * driver?: scalar|Param|null, // Default: "gd" * cache?: scalar|Param|null, // Default: "default" * cache_base_path?: scalar|Param|null, // Default: "" @@ -1627,18 +1627,18 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * redirect_response_code?: int|Param, // Default: 302 * }, * filter_sets?: array>, - * post_processors?: array>, - * }>, + * quality?: scalar|Param|null, + * jpeg_quality?: scalar|Param|null, + * png_compression_level?: scalar|Param|null, + * png_compression_filter?: scalar|Param|null, + * format?: scalar|Param|null, + * animated?: bool|Param, + * cache?: scalar|Param|null, + * data_loader?: scalar|Param|null, + * default_image?: scalar|Param|null, + * filters?: array>, + * post_processors?: array>, + * }>, * twig?: array{ * mode?: "none"|"lazy"|"legacy"|Param, // Twig mode: none/lazy/legacy (default) // Default: "legacy" * assets_version?: scalar|Param|null, // Default: null @@ -1853,8 +1853,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * clickjacking?: array{ * hosts?: list, * paths?: array, + * header?: scalar|Param|null, // Default: "DENY" + * }>, * content_types?: list, * }, * external_redirects?: array{ @@ -2019,12 +2019,12 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * cross_origin_isolation?: bool|array{ * enabled?: bool|Param, // Default: false * paths?: array, + * coep?: "unsafe-none"|"require-corp"|"credentialless"|Param, // Cross-Origin-Embedder-Policy (COEP) header value + * coop?: "unsafe-none"|"same-origin-allow-popups"|"same-origin"|"noopener-allow-popups"|Param, // Cross-Origin-Opener-Policy (COOP) header value + * corp?: "same-site"|"same-origin"|"cross-origin"|Param, // Cross-Origin-Resource-Policy (CORP) header value + * report_only?: bool|Param, // Use Report-Only headers instead of enforcing (applies to COEP and COOP only) // Default: false + * report_to?: scalar|Param|null, // Reporting endpoint name for violations (requires Reporting API configuration, applies to COEP and COOP only) // Default: null + * }>, * }, * } * @psalm-type TurboConfig = array{ @@ -2099,31 +2099,31 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * counter_checker?: scalar|Param|null, // This service will check if the counter is valid. By default it throws an exception (recommended). // Default: "Webauthn\\Counter\\ThrowExceptionIfInvalid" * top_origin_validator?: scalar|Param|null, // For cross origin (e.g. iframe), this service will be in charge of verifying the top origin. // Default: null * creation_profiles?: bool|array, - * public_key_credential_parameters?: list, - * attestation_conveyance?: scalar|Param|null, // Default: "none" - * conditional_create?: bool|Param, // Enable Conditional Create (auto-register) for this profile. When true, user presence can be false after password authentication. See https://github.com/w3c/webauthn/wiki/Explainer:-Conditional-Create // Default: false - * }>, - * request_profiles?: bool|array, - * }>, + * resident_key?: scalar|Param|null, // Default: "preferred" + * }, + * extensions?: array, + * public_key_credential_parameters?: list, + * attestation_conveyance?: scalar|Param|null, // Default: "none" + * conditional_create?: bool|Param, // Enable Conditional Create (auto-register) for this profile. When true, user presence can be false after password authentication. See https://github.com/w3c/webauthn/wiki/Explainer:-Conditional-Create // Default: false + * }>, + * request_profiles?: bool|array, + * }>, * client_override_policy?: array{ // Configuration for allowing client request values to override profile configuration * user_verification?: array{ * enabled?: bool|Param, // Whether to allow client requests to override the user verification requirement // Default: false @@ -2158,39 +2158,39 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * controllers?: bool|array{ * enabled?: bool|Param, // Default: false * creation?: array, - * allow_subdomains?: bool|Param, // Default: false - * secured_rp_ids?: array, - * }>, + * options_method?: scalar|Param|null, // Default: "POST" + * options_path?: scalar|Param|null, + * result_method?: scalar|Param|null, // Default: "POST" + * result_path?: scalar|Param|null, // Default: null + * host?: scalar|Param|null, // Default: null + * profile?: scalar|Param|null, // Default: "default" + * options_builder?: scalar|Param|null, // When set, corresponds to the ID of the Public Key Credential Creation Builder. The profile-based ebuilder is ignored. // Default: null + * user_entity_guesser?: scalar|Param|null, + * hide_existing_credentials?: scalar|Param|null, // In order to prevent username enumeration, the existing credentials can be hidden. This is highly recommended when the attestation ceremony is performed by anonymous users. // Default: false + * options_storage?: scalar|Param|null, // Deprecated: The child node "options_storage" at path "webauthn.controllers.creation..options_storage" is deprecated. Please use the root option "options_storage" instead. // Service responsible of the options/user entity storage during the ceremony // Default: null + * success_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Service\\DefaultSuccessHandler" + * failure_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Service\\DefaultFailureHandler" + * options_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultCreationOptionsHandler" + * allowed_origins?: array, + * allow_subdomains?: bool|Param, // Default: false + * secured_rp_ids?: array, + * }>, * request?: array, - * allow_subdomains?: bool|Param, // Default: false - * secured_rp_ids?: array, - * }>, + * options_method?: scalar|Param|null, // Default: "POST" + * options_path?: scalar|Param|null, + * result_method?: scalar|Param|null, // Default: "POST" + * result_path?: scalar|Param|null, // Default: null + * host?: scalar|Param|null, // Default: null + * profile?: scalar|Param|null, // Default: "default" + * options_builder?: scalar|Param|null, // When set, corresponds to the ID of the Public Key Credential Creation Builder. The profile-based ebuilder is ignored. // Default: null + * options_storage?: scalar|Param|null, // Deprecated: The child node "options_storage" at path "webauthn.controllers.request..options_storage" is deprecated. Please use the root option "options_storage" instead. // Service responsible of the options/user entity storage during the ceremony // Default: null + * success_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Service\\DefaultSuccessHandler" + * failure_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Service\\DefaultFailureHandler" + * options_handler?: scalar|Param|null, // Default: "Webauthn\\Bundle\\Security\\Handler\\DefaultRequestOptionsHandler" + * allowed_origins?: array, + * allow_subdomains?: bool|Param, // Default: false + * secured_rp_ids?: array, + * }>, * }, * passkey_endpoints?: bool|array{ // Enable the .well-known/passkey-endpoints discovery endpoint as defined in the W3C Passkey Endpoints specification. * enabled?: bool|Param, // Default: false @@ -2210,109 +2210,109 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * } * @psalm-type NbgrpOneloginSamlConfig = array{ // nb:group OneLogin PHP Symfony Bundle configuration * onelogin_settings?: array/saml/" - * strict?: bool|Param, - * debug?: bool|Param, - * idp?: array{ - * entityId?: scalar|Param|null, - * singleSignOnService?: array{ - * url?: scalar|Param|null, - * binding?: scalar|Param|null, - * }, - * singleLogoutService?: array{ - * url?: scalar|Param|null, - * responseUrl?: scalar|Param|null, - * binding?: scalar|Param|null, - * }, - * x509cert?: scalar|Param|null, - * certFingerprint?: scalar|Param|null, - * certFingerprintAlgorithm?: "sha1"|"sha256"|"sha384"|"sha512"|Param, - * x509certMulti?: array{ - * signing?: list, - * encryption?: list, - * }, + * baseurl?: scalar|Param|null, // Default: "/saml/" + * strict?: bool|Param, + * debug?: bool|Param, + * idp?: array{ + * entityId?: scalar|Param|null, + * singleSignOnService?: array{ + * url?: scalar|Param|null, + * binding?: scalar|Param|null, * }, - * sp?: array{ - * entityId?: scalar|Param|null, // Default: "/saml/metadata" - * assertionConsumerService?: array{ - * url?: scalar|Param|null, // Default: "/saml/acs" - * binding?: scalar|Param|null, - * }, - * attributeConsumingService?: array{ - * serviceName?: scalar|Param|null, - * serviceDescription?: scalar|Param|null, - * requestedAttributes?: list, - * }>, - * }, - * singleLogoutService?: array{ - * url?: scalar|Param|null, // Default: "/saml/logout" - * binding?: scalar|Param|null, - * }, - * NameIDFormat?: scalar|Param|null, - * x509cert?: scalar|Param|null, - * privateKey?: scalar|Param|null, - * x509certNew?: scalar|Param|null, + * singleLogoutService?: array{ + * url?: scalar|Param|null, + * responseUrl?: scalar|Param|null, + * binding?: scalar|Param|null, * }, - * compress?: array{ - * requests?: bool|Param, - * responses?: bool|Param, + * x509cert?: scalar|Param|null, + * certFingerprint?: scalar|Param|null, + * certFingerprintAlgorithm?: "sha1"|"sha256"|"sha384"|"sha512"|Param, + * x509certMulti?: array{ + * signing?: list, + * encryption?: list, * }, - * security?: array{ - * nameIdEncrypted?: bool|Param, - * authnRequestsSigned?: bool|Param, - * logoutRequestSigned?: bool|Param, - * logoutResponseSigned?: bool|Param, - * signMetadata?: bool|Param, - * wantMessagesSigned?: bool|Param, - * wantAssertionsEncrypted?: bool|Param, - * wantAssertionsSigned?: bool|Param, - * wantNameId?: bool|Param, - * wantNameIdEncrypted?: bool|Param, - * requestedAuthnContext?: mixed, - * requestedAuthnContextComparison?: "exact"|"minimum"|"maximum"|"better"|Param, - * wantXMLValidation?: bool|Param, - * relaxDestinationValidation?: bool|Param, - * destinationStrictlyMatches?: bool|Param, - * allowRepeatAttributeName?: bool|Param, - * rejectUnsolicitedResponsesWithInResponseTo?: bool|Param, - * signatureAlgorithm?: "http://www.w3.org/2000/09/xmldsig#rsa-sha1"|"http://www.w3.org/2000/09/xmldsig#dsa-sha1"|"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"|"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"|"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"|Param, - * digestAlgorithm?: "http://www.w3.org/2000/09/xmldsig#sha1"|"http://www.w3.org/2001/04/xmlenc#sha256"|"http://www.w3.org/2001/04/xmldsig-more#sha384"|"http://www.w3.org/2001/04/xmlenc#sha512"|Param, - * encryption_algorithm?: "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"|"http://www.w3.org/2001/04/xmlenc#aes128-cbc"|"http://www.w3.org/2001/04/xmlenc#aes192-cbc"|"http://www.w3.org/2001/04/xmlenc#aes256-cbc"|"http://www.w3.org/2009/xmlenc11#aes128-gcm"|"http://www.w3.org/2009/xmlenc11#aes192-gcm"|"http://www.w3.org/2009/xmlenc11#aes256-gcm"|Param, - * lowercaseUrlencoding?: bool|Param, + * }, + * sp?: array{ + * entityId?: scalar|Param|null, // Default: "/saml/metadata" + * assertionConsumerService?: array{ + * url?: scalar|Param|null, // Default: "/saml/acs" + * binding?: scalar|Param|null, * }, - * contactPerson?: array{ - * technical?: array{ - * givenName?: scalar|Param|null, - * emailAddress?: scalar|Param|null, - * }, - * support?: array{ - * givenName?: scalar|Param|null, - * emailAddress?: scalar|Param|null, - * }, - * administrative?: array{ - * givenName?: scalar|Param|null, - * emailAddress?: scalar|Param|null, - * }, - * billing?: array{ - * givenName?: scalar|Param|null, - * emailAddress?: scalar|Param|null, - * }, - * other?: array{ - * givenName?: scalar|Param|null, - * emailAddress?: scalar|Param|null, - * }, - * }, - * organization?: list, * }>, + * }, + * singleLogoutService?: array{ + * url?: scalar|Param|null, // Default: "/saml/logout" + * binding?: scalar|Param|null, + * }, + * NameIDFormat?: scalar|Param|null, + * x509cert?: scalar|Param|null, + * privateKey?: scalar|Param|null, + * x509certNew?: scalar|Param|null, + * }, + * compress?: array{ + * requests?: bool|Param, + * responses?: bool|Param, + * }, + * security?: array{ + * nameIdEncrypted?: bool|Param, + * authnRequestsSigned?: bool|Param, + * logoutRequestSigned?: bool|Param, + * logoutResponseSigned?: bool|Param, + * signMetadata?: bool|Param, + * wantMessagesSigned?: bool|Param, + * wantAssertionsEncrypted?: bool|Param, + * wantAssertionsSigned?: bool|Param, + * wantNameId?: bool|Param, + * wantNameIdEncrypted?: bool|Param, + * requestedAuthnContext?: mixed, + * requestedAuthnContextComparison?: "exact"|"minimum"|"maximum"|"better"|Param, + * wantXMLValidation?: bool|Param, + * relaxDestinationValidation?: bool|Param, + * destinationStrictlyMatches?: bool|Param, + * allowRepeatAttributeName?: bool|Param, + * rejectUnsolicitedResponsesWithInResponseTo?: bool|Param, + * signatureAlgorithm?: "http://www.w3.org/2000/09/xmldsig#rsa-sha1"|"http://www.w3.org/2000/09/xmldsig#dsa-sha1"|"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"|"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"|"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"|Param, + * digestAlgorithm?: "http://www.w3.org/2000/09/xmldsig#sha1"|"http://www.w3.org/2001/04/xmlenc#sha256"|"http://www.w3.org/2001/04/xmldsig-more#sha384"|"http://www.w3.org/2001/04/xmlenc#sha512"|Param, + * encryption_algorithm?: "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"|"http://www.w3.org/2001/04/xmlenc#aes128-cbc"|"http://www.w3.org/2001/04/xmlenc#aes192-cbc"|"http://www.w3.org/2001/04/xmlenc#aes256-cbc"|"http://www.w3.org/2009/xmlenc11#aes128-gcm"|"http://www.w3.org/2009/xmlenc11#aes192-gcm"|"http://www.w3.org/2009/xmlenc11#aes256-gcm"|Param, + * lowercaseUrlencoding?: bool|Param, + * }, + * contactPerson?: array{ + * technical?: array{ + * givenName?: scalar|Param|null, + * emailAddress?: scalar|Param|null, + * }, + * support?: array{ + * givenName?: scalar|Param|null, + * emailAddress?: scalar|Param|null, + * }, + * administrative?: array{ + * givenName?: scalar|Param|null, + * emailAddress?: scalar|Param|null, + * }, + * billing?: array{ + * givenName?: scalar|Param|null, + * emailAddress?: scalar|Param|null, + * }, + * other?: array{ + * givenName?: scalar|Param|null, + * emailAddress?: scalar|Param|null, + * }, + * }, + * organization?: list, + * }>, * use_proxy_vars?: bool|Param, // Default: false * idp_parameter_name?: scalar|Param|null, // Default: "idp" * entity_manager_name?: scalar|Param|null, @@ -2346,11 +2346,11 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * auto_install?: bool|Param, // Default: false * fonts?: list, + * normal?: scalar|Param|null, + * bold?: scalar|Param|null, + * italic?: scalar|Param|null, + * bold_italic?: scalar|Param|null, + * }>, * } * @psalm-type KnpuOauth2ClientConfig = array{ * http_client?: scalar|Param|null, // Service id of HTTP client to use (must implement GuzzleHttp\ClientInterface) // Default: null @@ -2376,18 +2376,18 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * skip_same_as_origin?: bool|Param, // Default: true * }, * paths?: array, - * allow_headers?: list, - * allow_methods?: list, - * allow_private_network?: bool|Param, - * expose_headers?: list, - * max_age?: scalar|Param|null, // Default: 0 - * hosts?: list, - * origin_regex?: bool|Param, - * forced_allow_origin_value?: scalar|Param|null, // Default: null - * skip_same_as_origin?: bool|Param, - * }>, + * allow_credentials?: bool|Param, + * allow_origin?: list, + * allow_headers?: list, + * allow_methods?: list, + * allow_private_network?: bool|Param, + * expose_headers?: list, + * max_age?: scalar|Param|null, // Default: 0 + * hosts?: list, + * origin_regex?: bool|Param, + * forced_allow_origin_value?: scalar|Param|null, // Default: null + * skip_same_as_origin?: bool|Param, + * }>, * } * @psalm-type JbtronicsSettingsConfig = array{ * search_paths?: list, @@ -2518,13 +2518,13 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * persist_authorization?: bool|Param, // Persist the SwaggerUI Authorization in the localStorage. // Default: false * versions?: list, * api_keys?: array, + * name?: scalar|Param|null, // The name of the header or query parameter containing the api key. + * type?: "query"|"header"|Param, // Whether the api key should be a query parameter or a header. + * }>, * http_auth?: array, + * scheme?: scalar|Param|null, // The OpenAPI HTTP auth scheme, for example "bearer" + * bearerFormat?: scalar|Param|null, // The OpenAPI HTTP bearer format + * }>, * swagger_ui_extra_configuration?: mixed, // To pass extra configuration to Swagger UI, like docExpansion or filter. // Default: [] * }, * http_cache?: array{ @@ -2565,9 +2565,9 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * termsOfService?: scalar|Param|null, // A URL to the Terms of Service for the API. MUST be in the format of a URL. // Default: null * tags?: list, + * name?: scalar|Param|null, + * description?: scalar|Param|null, // Default: null + * }>, * license?: array{ * name?: scalar|Param|null, // The license name used for the API. // Default: null * url?: scalar|Param|null, // URL to the license used for the API. MUST be in the format of a URL. // Default: null @@ -2589,17 +2589,17 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * exception_to_status?: array, * formats?: array, - * }>, + * mime_types?: list, + * }>, * patch_formats?: array, - * }>, + * mime_types?: list, + * }>, * docs_formats?: array, - * }>, + * mime_types?: list, + * }>, * error_formats?: array, - * }>, + * mime_types?: list, + * }>, * jsonschema_formats?: list, * defaults?: array{ * uri_template?: mixed, @@ -2671,30 +2671,30 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * policy?: mixed, * middleware?: mixed, * parameters?: array - * }>, + * key?: mixed, + * schema?: mixed, + * open_api?: mixed, + * provider?: mixed, + * filter?: mixed, + * property?: mixed, + * description?: mixed, + * properties?: mixed, + * required?: mixed, + * priority?: mixed, + * hydra?: mixed, + * constraints?: mixed, + * security?: mixed, + * security_message?: mixed, + * extra_properties?: mixed, + * filter_context?: mixed, + * native_type?: mixed, + * cast_to_array?: mixed, + * cast_to_native_type?: mixed, + * cast_fn?: mixed, + * default?: mixed, + * filter_class?: mixed, + * ... + * }>, * strict_query_parameter_validation?: mixed, * hide_hydra_operation?: mixed, * json_stream?: mixed, @@ -2735,22 +2735,22 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * cache_retention?: "none"|"short"|"long"|Param, // Prompt cache retention policy for Anthropic models // Default: "short" * }, * azure?: array, + * api_key?: string|Param, + * base_url?: string|Param, + * deployment?: string|Param, + * api_version?: string|Param, // The used API version + * http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client" + * }>, * bedrock?: array, + * bedrock_runtime_client?: string|Param, // Service ID of the Bedrock runtime client to use // Default: null + * model_catalog?: string|Param, // Default: null + * }>, * cache?: array, + * platform?: string|Param, + * service?: string|Param, // The cache service id as defined under the "cache" configuration key // Default: "cache.app" + * cache_key?: string|Param, // Key used to store platform results, if not set, the current platform name will be used, the "prompt_cache_key" can be set during platform call to override this value + * ttl?: int|Param, + * }>, * cartesia?: array{ * api_key?: string|Param, * version?: string|Param, @@ -2783,23 +2783,23 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client" * }, * failover?: array, - * rate_limiter?: string|Param, - * }>, + * platforms?: list, + * rate_limiter?: string|Param, + * }>, * gemini?: array{ * api_key?: string|Param, * http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client" * }, * generic?: array, + * base_url?: string|Param, + * api_key?: string|Param, + * http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client" + * model_catalog?: string|Param, // Service ID of the model catalog to use + * supports_completions?: bool|Param, // Default: true + * supports_embeddings?: bool|Param, // Default: true + * completions_path?: string|Param, // Default: "/v1/chat/completions" + * embeddings_path?: string|Param, // Default: "/v1/embeddings" + * }>, * huggingface?: array{ * api_key?: string|Param, * provider?: string|Param, // Default: "hf-inference" @@ -2852,328 +2852,328 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * }, * }, * model?: array|\Symfony\AI\Platform\Capability|Param>, - * }>>, + * class?: string|Param, // The fully qualified class name of the model (must extend Symfony\AI\Platform\Model) // Default: "Symfony\\AI\\Platform\\Model" + * capabilities?: list|\Symfony\AI\Platform\Capability|Param>, + * }>>, * agent?: array, - * }, - * keep_tool_messages?: bool|Param, // Keep tool messages in the conversation history // Default: false - * include_sources?: bool|Param, // Include sources exposed by tools as part of the tool result metadata // Default: false - * fault_tolerant_toolbox?: bool|Param, // Continue the agent run even if a tool call fails // Default: true - * speech?: bool|array{ // Speech (TTS/STT) decorator configuration - * enabled?: bool|Param, // Default: true - * text_to_speech_platform?: string|Param, // Service name of the TTS platform (e.g. ai.platform.elevenlabs). // Default: null - * speech_to_text_platform?: string|Param, // Service name of the STT platform (e.g. ai.platform.openai). // Default: null - * tts_model?: string|Param, // Text-to-speech model name // Default: null - * tts_options?: mixed, // Provider-specific TTS options // Default: [] - * stt_model?: string|Param, // Speech-to-text model name // Default: null - * stt_options?: mixed, // Provider-specific STT options // Default: [] - * }, - * }>, + * platform?: string|Param, // Service name of platform // Default: "Symfony\\AI\\Platform\\PlatformInterface" + * model?: mixed, + * memory?: mixed, // Memory configuration: string for static memory, or array with "service" key for service reference // Default: null + * prompt?: string|array{ // The system prompt configuration + * text?: string|Param, // The system prompt text + * file?: string|Param, // Path to file containing the system prompt + * include_tools?: bool|Param, // Include tool definitions at the end of the system prompt // Default: false + * enable_translation?: bool|Param, // Enable translation for the system prompt // Default: false + * translation_domain?: string|Param, // The translation domain for the system prompt // Default: null + * }, + * tools?: bool|array{ + * enabled?: bool|Param, // Default: true + * services?: list, + * }, + * keep_tool_messages?: bool|Param, // Keep tool messages in the conversation history // Default: false + * include_sources?: bool|Param, // Include sources exposed by tools as part of the tool result metadata // Default: false + * fault_tolerant_toolbox?: bool|Param, // Continue the agent run even if a tool call fails // Default: true + * speech?: bool|array{ // Speech (TTS/STT) decorator configuration + * enabled?: bool|Param, // Default: true + * text_to_speech_platform?: string|Param, // Service name of the TTS platform (e.g. ai.platform.elevenlabs). // Default: null + * speech_to_text_platform?: string|Param, // Service name of the STT platform (e.g. ai.platform.openai). // Default: null + * tts_model?: string|Param, // Text-to-speech model name // Default: null + * tts_options?: mixed, // Provider-specific TTS options // Default: [] + * stt_model?: string|Param, // Speech-to-text model name // Default: null + * stt_options?: mixed, // Provider-specific STT options // Default: [] + * }, + * }>, * multi_agent?: array>, - * fallback?: string|Param, // Service ID of the fallback agent for unmatched requests - * }>, + * orchestrator?: string|Param, // Service ID of the orchestrator agent + * handoffs?: array>, + * fallback?: string|Param, // Service ID of the fallback agent for unmatched requests + * }>, * store?: array{ * azuresearch?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * api_version?: string|Param, + * index_name?: string|Param, // The name of the store will be used if the "index_name" option is not set + * http_client?: string|Param, // Default: "http_client" + * vector_field?: string|Param, // Default: "vector" + * }>, * cache?: array, + * service?: string|Param, // Default: "cache.app" + * cache_key?: string|Param, // The name of the store will be used if the key is not set. + * strategy?: string|Param, // Default: "cosine" + * }>, * chromadb?: array, + * client?: string|Param, // Default: "Codewithkyrian\\ChromaDB\\Client" + * collection?: string|Param, + * }>, * clickhouse?: array, + * dsn?: string|Param, + * http_client?: string|Param, + * database?: string|Param, + * table?: string|Param, + * }>, * cloudflare?: array, + * account_id?: string|Param, + * api_key?: string|Param, + * index_name?: string|Param, + * dimensions?: int|Param, // Default: 1536 + * metric?: string|Param, // Default: "cosine" + * endpoint?: string|Param, + * }>, * elasticsearch?: array, + * endpoint?: string|Param, + * index_name?: string|Param, + * vectors_field?: string|Param, // Default: "_vectors" + * dimensions?: int|Param, // Default: 1536 + * similarity?: string|Param, // Default: "cosine" + * http_client?: string|Param, // Default: "http_client" + * }>, * manticoresearch?: array, + * endpoint?: string|Param, + * table?: string|Param, + * field?: string|Param, // Default: "_vectors" + * type?: string|Param, // Default: "hnsw" + * similarity?: string|Param, // Default: "cosine" + * dimensions?: int|Param, // Default: 1536 + * quantization?: string|Param, + * }>, * mariadb?: array, + * connection?: string|Param, + * table_name?: string|Param, + * index_name?: string|Param, + * vector_field_name?: string|Param, + * setup_options?: array{ + * dimensions?: int|Param, + * }, + * distance?: "cosine"|"euclidean"|"distance"|Param, // Distance metric to use for vector similarity search // Default: "euclidean" + * }>, * meilisearch?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * index_name?: string|Param, + * embedder?: string|Param, // Default: "default" + * vector_field?: string|Param, // Default: "_vectors" + * dimensions?: int|Param, // Default: 1536 + * semantic_ratio?: float|Param, // The ratio between semantic (vector) and full-text search (0.0 to 1.0). Default: 1.0 (100% semantic) // Default: 1.0 + * }>, * memory?: array, + * strategy?: string|Param, + * }>, * milvus?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * database?: string|Param, + * collection?: string|Param, + * vector_field?: string|Param, // Default: "_vectors" + * dimensions?: int|Param, // Default: 1536 + * metric_type?: string|Param, // Default: "COSINE" + * }>, * mongodb?: array, + * client?: string|Param, // Default: "MongoDB\\Client" + * database?: string|Param, + * collection?: string|Param, + * index_name?: string|Param, + * vector_field?: string|Param, // Default: "vector" + * bulk_write?: bool|Param, // Default: false + * setup_options?: array{ + * fields?: mixed, // Default: [] + * }, + * }>, * neo4j?: array, + * endpoint?: string|Param, + * username?: string|Param, + * password?: string|Param, + * database?: string|Param, + * vector_index_name?: string|Param, + * node_name?: string|Param, + * vector_field?: string|Param, // Default: "embeddings" + * dimensions?: int|Param, // Default: 1536 + * distance?: string|Param, // Default: "cosine" + * quantization?: bool|Param, + * }>, * opensearch?: array, + * endpoint?: string|Param, + * index_name?: string|Param, + * vectors_field?: string|Param, // Default: "_vectors" + * dimensions?: int|Param, // Default: 1536 + * space_type?: string|Param, // Default: "l2" + * http_client?: string|Param, // Default: "http_client" + * }>, * pinecone?: array, - * top_k?: int|Param, - * }>, + * client?: string|Param, // Default: "Probots\\Pinecone\\Client" + * index_name?: string|Param, + * namespace?: string|Param, + * filter?: list, + * top_k?: int|Param, + * }>, * postgres?: array, + * dsn?: string|Param, + * username?: string|Param, + * password?: string|Param, + * table_name?: string|Param, + * vector_field?: string|Param, // Default: "embedding" + * distance?: "cosine"|"inner_product"|"l1"|"l2"|Param, // Distance metric to use for vector similarity search // Default: "l2" + * dbal_connection?: string|Param, + * setup_options?: array{ + * vector_type?: string|Param, // Default: "vector" + * vector_size?: int|Param, // Default: 1536 + * index_method?: string|Param, // Default: "ivfflat" + * index_opclass?: string|Param, // Default: "vector_cosine_ops" + * }, + * }>, * qdrant?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * collection_name?: string|Param, // The name of the store will be used if the "collection_name" is not set + * http_client?: string|Param, // Default: "http_client" + * dimensions?: int|Param, // Default: 1536 + * distance?: string|Param, // Default: "Cosine" + * async?: bool|Param, // Default: false + * }>, * redis?: array, + * connection_parameters?: mixed, // see https://github.com/phpredis/phpredis?tab=readme-ov-file#example-1 + * client?: string|Param, // a service id of a Redis client + * index_name?: string|Param, + * key_prefix?: string|Param, // Default: "vector:" + * distance?: "COSINE"|"L2"|"IP"|Param, // Distance metric to use for vector similarity search // Default: "COSINE" + * }>, * s3vectors?: array, - * vector_bucket_name?: string|Param, - * index_name?: string|Param, - * filter?: array, - * top_k?: int|Param, // Default number of results to return // Default: 3 - * }>, + * client?: string|Param, // Service reference to an existing S3VectorsClient + * configuration?: array, + * vector_bucket_name?: string|Param, + * index_name?: string|Param, + * filter?: array, + * top_k?: int|Param, // Default number of results to return // Default: 3 + * }>, * sqlite?: array, + * dsn?: string|Param, + * connection?: string|Param, + * table_name?: string|Param, + * strategy?: string|Param, + * vec?: bool|Param, // Default: false + * distance?: "cosine"|"L2"|Param, // Default: "cosine" + * vector_dimension?: int|Param, // Default: 1536 + * }>, * supabase?: array, + * http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client" + * url?: string|Param, + * api_key?: string|Param, + * table?: string|Param, + * vector_field?: string|Param, // Default: "embedding" + * vector_dimension?: int|Param, // Default: 1536 + * function_name?: string|Param, // Default: "match_documents" + * }>, * surrealdb?: array, + * endpoint?: string|Param, + * username?: string|Param, + * password?: string|Param, + * namespace?: string|Param, + * database?: string|Param, + * table?: string|Param, + * vector_field?: string|Param, // Default: "_vectors" + * strategy?: string|Param, // Default: "cosine" + * dimensions?: int|Param, // Default: 1536 + * namespaced_user?: bool|Param, + * }>, * typesense?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * collection?: string|Param, + * vector_field?: string|Param, // Default: "_vectors" + * dimensions?: int|Param, // Default: 1536 + * }>, * weaviate?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * http_client?: string|Param, // Default: "http_client" + * collection?: string|Param, // The name of the store will be used if the "collection" is not set + * }>, * vektor?: array, + * storage_path?: string|Param, // Default: "%kernel.project_dir%/var/share" + * dimensions?: int|Param, // Default: 1536 + * }>, * }, * message_store?: array{ * cache?: array, + * service?: string|Param, // Default: "cache.app" + * key?: string|Param, // The name of the message store will be used if the key is not set + * ttl?: int|Param, + * }>, * cloudflare?: array, + * account_id?: string|Param, + * api_key?: string|Param, + * namespace?: string|Param, + * endpoint_url?: string|Param, // If the version of the Cloudflare API is updated, use this key to support it. + * }>, * doctrine?: array{ * dbal?: array, + * connection?: string|Param, + * table_name?: string|Param, // The name of the message store will be used if the table_name is not set + * }>, * }, * meilisearch?: array, + * endpoint?: string|Param, + * api_key?: string|Param, + * index_name?: string|Param, + * }>, * memory?: array, + * identifier?: string|Param, + * }>, * mongodb?: array, + * client?: string|Param, // Default: "MongoDB\\Client" + * database?: string|Param, + * collection?: string|Param, + * }>, * pogocache?: array, + * endpoint?: string|Param, + * password?: string|Param, + * key?: string|Param, + * }>, * redis?: array, + * connection_parameters?: mixed, // see https://github.com/phpredis/phpredis?tab=readme-ov-file#example-1 + * client?: string|Param, // a service id of a Redis client + * endpoint?: string|Param, + * index_name?: string|Param, + * }>, * session?: array, + * identifier?: string|Param, + * }>, * surrealdb?: array, + * endpoint?: string|Param, + * username?: string|Param, + * password?: string|Param, + * namespace?: string|Param, + * database?: string|Param, + * table?: string|Param, + * namespaced_user?: bool|Param, // Using a namespaced user is a good practice to prevent any undesired access to a specific table, see https://surrealdb.com/docs/surrealdb/reference-guide/security-best-practices + * }>, * }, * chat?: array, + * agent?: string|Param, + * message_store?: string|Param, + * }>, * vectorizer?: array, + * platform?: string|Param, // Service name of platform // Default: "Symfony\\AI\\Platform\\PlatformInterface" + * model?: mixed, + * }>, * indexer?: array, - * filters?: list, - * vectorizer?: scalar|Param|null, // Service name of vectorizer // Default: "Symfony\\AI\\Store\\Document\\VectorizerInterface" - * store?: string|Param, // Service name of store // Default: "Symfony\\AI\\Store\\StoreInterface" - * }>, + * loader?: string|Param, // Service name of loader // Default: null + * source?: mixed, // Source identifier (file path, URL, etc.) or array of sources // Default: null + * transformers?: list, + * filters?: list, + * vectorizer?: scalar|Param|null, // Service name of vectorizer // Default: "Symfony\\AI\\Store\\Document\\VectorizerInterface" + * store?: string|Param, // Service name of store // Default: "Symfony\\AI\\Store\\StoreInterface" + * }>, * retriever?: array, + * vectorizer?: scalar|Param|null, // Service name of vectorizer // Default: "Symfony\\AI\\Store\\Document\\VectorizerInterface" + * store?: string|Param, // Service name of store // Default: "Symfony\\AI\\Store\\StoreInterface" + * }>, * } * @psalm-type ConfigType = array{ * imports?: ImportsConfig, diff --git a/src/Helpers/RandomizeUseragentHttpClient.php b/src/Helpers/RandomizeUseragentHttpClient.php index bca91c79..42e62d11 100644 --- a/src/Helpers/RandomizeUseragentHttpClient.php +++ b/src/Helpers/RandomizeUseragentHttpClient.php @@ -29,60 +29,137 @@ use Symfony\Contracts\HttpClient\ResponseStreamInterface; /** * HttpClient wrapper that randomizes the user agent for each request, to make it harder for servers to detect and block us. + * It also sets some other headers to make the requests look more like real browser requests. * When we get a 503, 403 or 429, we assume that the server is blocking us and try again with a different user agent, until we run out of retries. */ final class RandomizeUseragentHttpClient implements HttpClientInterface { - public const USER_AGENTS = [ - "Mozilla/5.0 (Windows; U; Windows NT 10.0; Win64; x64) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/52.0.1359.302 Safari/600.6 Edge/15.25690", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 8_8_3) Gecko/20100101 Firefox/51.6", - "Mozilla/5.0 (Android; Android 4.4.4; E:number:20-23:00 Build/24.0.B.1.34) AppleWebKit/603.18 (KHTML, like Gecko) Chrome/47.0.1559.384 Mobile Safari/600.5", - "Mozilla/5.0 (compatible; MSIE 9.0; Windows; Windows NT 6.3; WOW64 Trident/5.0)", - "Mozilla/5.0 (Windows; Windows NT 6.0; Win64; x64) AppleWebKit/602.21 (KHTML, like Gecko) Chrome/51.0.3187.154 Safari/536", - "Mozilla/5.0 (iPhone; CPU iPhone OS 9_4_2; like Mac OS X) AppleWebKit/537.24 (KHTML, like Gecko) Chrome/51.0.2432.275 Mobile Safari/535.6", - "Mozilla/5.0 (U; Linux i680 ) Gecko/20100101 Firefox/57.5", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 8_8_6; en-US) Gecko/20100101 Firefox/53.9", - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 8_6_7) AppleWebKit/534.46 (KHTML, like Gecko) Chrome/55.0.3276.345 Safari/535", - "Mozilla/5.0 (Windows; Windows NT 10.5;) AppleWebKit/535.42 (KHTML, like Gecko) Chrome/53.0.1176.353 Safari/534.0 Edge/11.95743", - "Mozilla/5.0 (Linux; Android 5.1.1; MOTO G Build/LPH223) AppleWebKit/600.27 (KHTML, like Gecko) Chrome/47.0.1604.204 Mobile Safari/535.1", - "Mozilla/5.0 (iPod; CPU iPod OS 7_4_8; like Mac OS X) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/50.0.1632.146 Mobile Safari/600.4", - "Mozilla/5.0 (Linux; U; Linux i570 ; en-US) Gecko/20100101 Firefox/49.9", - "Mozilla/5.0 (Windows NT 10.2; WOW64; en-US) AppleWebKit/603.2 (KHTML, like Gecko) Chrome/55.0.1299.311 Safari/535", - "Mozilla/5.0 (Windows; Windows NT 10.5; x64; en-US) AppleWebKit/603.39 (KHTML, like Gecko) Chrome/52.0.1443.139 Safari/536.6 Edge/13.79436", - "Mozilla/5.0 (Linux; U; Android 5.1; SM-G9350T Build/MMB29M) AppleWebKit/537.15 (KHTML, like Gecko) Chrome/55.0.2552.307 Mobile Safari/600.8", - "Mozilla/5.0 (Android; Android 6.0; SAMSUNG SM-D9350V Build/MDB08L) AppleWebKit/535.30 (KHTML, like Gecko) Chrome/53.0.1345.278 Mobile Safari/537.4", - "Mozilla/5.0 (Windows; Windows NT 10.0;) AppleWebKit/534.44 (KHTML, like Gecko) Chrome/47.0.3503.387 Safari/601", + private const PROFILES = [ + // --- CHROME ON WINDOWS --- + 'chrome_windows' => [ + 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36', + 'Sec-Ch-Ua' => '"Google Chrome";v="142", "Chromium";v="142", "Not=A?Brand";v="99"', + 'Sec-Ch-Ua-Mobile' => '?0', + 'Sec-Ch-Ua-Platform' => '"Windows"', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + ], + + // --- CHROME ON MACOS --- + 'chrome_mac' => [ + 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36', + 'Sec-Ch-Ua' => '"Google Chrome";v="141", "Chromium";v="141", "Not=A?Brand";v="99"', + 'Sec-Ch-Ua-Mobile' => '?0', + 'Sec-Ch-Ua-Platform' => '"macOS"', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + ], + + // --- EDGE ON WINDOWS --- + 'edge_windows' => [ + 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', + 'Sec-Ch-Ua' => '"Microsoft Edge";v="142", "Chromium";v="142", "Not=A?Brand";v="99"', + 'Sec-Ch-Ua-Mobile' => '?0', + 'Sec-Ch-Ua-Platform' => '"Windows"', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + ], + + // --- FIREFOX ON WINDOWS --- + 'firefox_windows' => [ + 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8', + 'Accept-Language' => 'en-US,en;q=0.5', + // Firefox does not send Sec-Ch-Ua headers by default + ], + + // --- FIREFOX ON LINUX --- + 'firefox_linux' => [ + 'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8', + 'Accept-Language' => 'en-US,en;q=0.5', + ], + + // --- SAFARI ON MACOS --- + 'safari_mac' => [ + 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language' => 'en-US,en;q=0.9', + ], + + // --- CHROME ON ANDROID (Mobile) --- + 'chrome_android' => [ + 'User-Agent' => 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Mobile Safari/537.36', + 'Sec-Ch-Ua' => '"Google Chrome";v="142", "Chromium";v="142", "Not=A?Brand";v="99"', + 'Sec-Ch-Ua-Mobile' => '?1', + 'Sec-Ch-Ua-Platform' => '"Android"', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + ], + + // --- SAFARI ON IPHONE (Mobile) --- + 'safari_iphone' => [ + 'User-Agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language' => 'en-US,en;q=0.9', + ], ]; + private const COMMON_HEADERS = [ + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language' => 'en-US,en;q=0.9', + 'Sec-Fetch-Dest' => 'document', + 'Sec-Fetch-Mode' => 'navigate', + 'Sec-Fetch-Site' => 'none', + 'Sec-Fetch-User' => '?1', + 'Upgrade-Insecure-Requests' => '1', + ]; + + private const ENTRY_REFERERS = [ + 'https://www.google.com/', + 'https://www.bing.com/', + 'https://duckduckgo.com/', + 'https://t.co/', // Twitter/X shortener + 'https://www.reddit.com/', + ]; + + private ?string $lastUrl = null; + public function __construct( private readonly HttpClientInterface $client, - private readonly array $userAgents = self::USER_AGENTS, private readonly int $repeatOnFailure = 1, ) { } - public function getRandomUserAgent(): string - { - return $this->userAgents[array_rand($this->userAgents)]; - } - public function request(string $method, string $url, array $options = []): ResponseInterface { $repeatsLeft = $this->repeatOnFailure; do { - $modifiedOptions = $options; - if (!isset($modifiedOptions['headers']['User-Agent'])) { - $modifiedOptions['headers']['User-Agent'] = $this->getRandomUserAgent(); + $profile = self::PROFILES[array_rand(self::PROFILES)]; + + // Merge common headers with the specific browser profile + $headers = array_merge(self::COMMON_HEADERS, $profile); + + //Add a Referer header if not already set, to make it look more like a real browser request. We use the last URL we visited as the referer, to simulate internal navigation. If we don't have a last URL (first request), we pick a random entry point from common referers. + if (!isset($options['headers']['Referer'])) { + if ($this->lastUrl !== null) { + // If we have a previous URL, use it (Internal Navigation) + $headers['Referer'] = $this->lastUrl; + } else { + // First request? Pick an entry point (External Entry) + $headers['Referer'] = self::ENTRY_REFERERS[array_rand(self::ENTRY_REFERERS)]; + } } - $response = $this->client->request($method, $url, $modifiedOptions); + + // Allow manual overrides from $options + $options['headers'] = array_merge($headers, $options['headers'] ?? []); + + $response = $this->client->request($method, $url, $options); //When we get a 503, 403 or 429, we assume that the server is blocking us and try again with a different user agent if (!in_array($response->getStatusCode(), [403, 429, 503], true)) { + $this->lastUrl = $url; // Update last visited URL for referer in the next request return $response; } //Otherwise we try again with a different user agent, until we run out of retries + usleep(5000); // Sleep for 5ms to avoid hammering the server too hard in case of multiple retries } while ($repeatsLeft-- > 0); return $response; @@ -95,6 +172,6 @@ final class RandomizeUseragentHttpClient implements HttpClientInterface public function withOptions(array $options): static { - return new self($this->client->withOptions($options), $this->userAgents, $this->repeatOnFailure); + return new self($this->client->withOptions($options), $this->repeatOnFailure); } } diff --git a/src/Services/Attachments/AttachmentManager.php b/src/Services/Attachments/AttachmentManager.php index 1075141b..c661b0f4 100644 --- a/src/Services/Attachments/AttachmentManager.php +++ b/src/Services/Attachments/AttachmentManager.php @@ -156,8 +156,8 @@ class AttachmentManager //Taken from: https://www.php.net/manual/de/function.filesize.php#106569 and slightly modified $sz = 'BKMGTP'; - $factor = (int) floor((strlen((string) $bytes) - 1) / 3); + $factor = min((int) floor((strlen((string) $bytes) - 1) / 3), strlen($sz) - 1); //Use real (10 based) SI prefixes - return sprintf("%.{$decimals}f", $bytes / 1000 ** $factor).@$sz[$factor]; + return sprintf("%.{$decimals}f", $bytes / 1000 ** $factor).$sz[$factor]; } } diff --git a/src/Services/Formatters/SIFormatter.php b/src/Services/Formatters/SIFormatter.php index b83501fa..1f25dbe6 100644 --- a/src/Services/Formatters/SIFormatter.php +++ b/src/Services/Formatters/SIFormatter.php @@ -59,10 +59,10 @@ class SIFormatter $prefixes_neg = ['', 'm', 'μ', 'n', 'p', 'f', 'a', 'z', 'y']; if ($magnitude >= 0) { - $nearest = (int) floor(abs($magnitude) / 3); + $nearest = min((int) floor(abs($magnitude) / 3), count($prefixes_pos) - 1); $symbol = $prefixes_pos[$nearest]; } else { - $nearest = (int) round(abs($magnitude) / 3); + $nearest = min((int) round(abs($magnitude) / 3), count($prefixes_neg) - 1); $symbol = $prefixes_neg[$nearest]; } diff --git a/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php b/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php index 64127341..08b1c301 100644 --- a/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php +++ b/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php @@ -89,7 +89,7 @@ trait PKImportHelperTrait //Use mime type to determine the extension like PartKeepr does in legacy implementation (just use the second part of the mime type) //See UploadedFile.php:291 in PartKeepr (https://github.com/partkeepr/PartKeepr/blob/f6176c3354b24fa39ac8bc4328ee0df91de3d5b6/src/PartKeepr/UploadedFileBundle/Entity/UploadedFile.php#L291) if (!empty ($attachment_row['mimetype'])) { - $attachment_row['extension'] = explode('/', (string) $attachment_row['mimetype'])[1]; + $attachment_row['extension'] = explode('/', (string) $attachment_row['mimetype'])[1] ?? ''; } else { //If the mime type is empty, we use the original extension $attachment_row['extension'] = pathinfo((string) $attachment_row['originalname'], PATHINFO_EXTENSION); diff --git a/src/Services/InfoProviderSystem/Providers/AIWebProvider.php b/src/Services/InfoProviderSystem/Providers/AIWebProvider.php index 7f4a3586..79f07be8 100644 --- a/src/Services/InfoProviderSystem/Providers/AIWebProvider.php +++ b/src/Services/InfoProviderSystem/Providers/AIWebProvider.php @@ -39,6 +39,7 @@ use Psr\Cache\CacheItemPoolInterface; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\UriResolver; use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient; use Symfony\Component\Intl\Languages; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -146,7 +147,7 @@ final class AIWebProvider implements InfoProviderInterface $html = $response->getContent(); //Convert html to markdown, to provide a cleaner input to the LLM. - $markdown = $this->htmlToMarkdown($html); + $markdown = $this->htmlToMarkdown($html, $url); //Truncate markdown to max content length, if needed $markdown = u($markdown)->truncate($this->settings->maxContentLength, '... [truncated]')->toString(); @@ -182,10 +183,34 @@ final class AIWebProvider implements InfoProviderInterface return json_encode($items->toObject(), JSON_THROW_ON_ERROR); } - private function htmlToMarkdown(string $html): string + private function htmlToMarkdown(string $html, string $url): string { - //Extract only the main content of the page to avoid overwhelming the LLM with irrelevant information. + $crawler = new Crawler($html); + + //Replace relative URLs with absolute URLs, to ensure that the LLM has full context and can access the links if needed. + $baseUrl = $crawler->getBaseHref() ?? $url; + + //Replace all relative links with their absolute counnterparts, to provide more context to the LLM and to ensure that any links included in the markdown are valid and can be accessed if needed. + $crawler->filter('a')->each(function (Crawler $node) use ($baseUrl) { + $href = $node->attr('href'); + if ($href) { + $absoluteUrl = UriResolver::resolve($href, $baseUrl); + //@phpstan-ignore-next-line we know that getNode(0) will always return a DOMElement, because the crawler is initialized with valid HTML and we are filtering for 'a' tags, which are always DOMElements. + $node->getNode(0)->setAttribute('href', $absoluteUrl); + } + }); + + $crawler->filter('img')->each(function (Crawler $node) use ($baseUrl) { + $src = $node->attr('src'); + if ($src) { + $absoluteUrl = UriResolver::resolve($src, $baseUrl); + //@phpstan-ignore-next-line we know that getNode(0) will always return a DOMElement, because the crawler is initialized with valid HTML and we are filtering for 'a' tags, which are always DOMElements. + $node->getNode(0)->setAttribute('src', $absoluteUrl); + } + }); + + //Extract only the main content of the page to avoid overwhelming the LLM with irrelevant information. $mainContent = $crawler->filter('main, article, #content'); // If we found a specific content area, get its HTML; otherwise, use the whole body. @@ -198,7 +223,7 @@ final class AIWebProvider implements InfoProviderInterface } } else { //Use the whole body content, as it might contain relevant information, especially for simpler pages that don't have a clear main/content section. - $htmlToConvert = $html; + $htmlToConvert = $crawler->outerHtml(); } diff --git a/src/Services/System/GitVersionInfoProvider.php b/src/Services/System/GitVersionInfoProvider.php index 01925ff8..927326e5 100644 --- a/src/Services/System/GitVersionInfoProvider.php +++ b/src/Services/System/GitVersionInfoProvider.php @@ -62,6 +62,9 @@ final readonly class GitVersionInfoProvider { if (is_file($this->getGitDirectory() . '/HEAD')) { $git = file($this->getGitDirectory() . '/HEAD'); + if ($git === false) { + return null; + } $head = explode('/', $git[0], 3); if (!isset($head[2])) { diff --git a/templates/admin/update_manager/index.html.twig b/templates/admin/update_manager/index.html.twig index 0b4eeceb..3e4483a6 100644 --- a/templates/admin/update_manager/index.html.twig +++ b/templates/admin/update_manager/index.html.twig @@ -296,17 +296,21 @@

{% trans %}update_manager.docker.setup_description{% endtrans %}

{% trans %}update_manager.docker.setup_step1{% endtrans %}
-
services:
-  watchtower:
-    image: containrrr/watchtower
-    volumes:
-      - /var/run/docker.sock:/var/run/docker.sock
-    environment:
-      - WATCHTOWER_HTTP_API_UPDATE=true
-      - WATCHTOWER_HTTP_API_TOKEN=your-secret-token
-      - WATCHTOWER_LABEL_ENABLE=true
-    ports:
-      - "8080:8080"
+

+                                # See documentation for full example: https://docs.part-db.de/installation/installation_docker.html
+                                services:
+                                  watchtower:
+                                    image: ghcr.io/nicholas-fedor/watchtower:latest
+                                    container_name: watchtower
+                                    restart: unless-stopped
+                                    volumes:
+                                      - /var/run/docker.sock:/var/run/docker.sock
+                                    environment:
+                                      - WATCHTOWER_HTTP_API_UPDATE=true
+                                      - WATCHTOWER_HTTP_API_TOKEN=your-secret-token
+                                      - WATCHTOWER_LABEL_ENABLE=true
+                                      - WATCHTOWER_CLEANUP=true
+                            
{% trans %}update_manager.docker.setup_step2{% endtrans %}
WATCHTOWER_API_URL=http://watchtower:8080
diff --git a/tests/Controller/AuthorizationTest.php b/tests/Controller/AuthorizationTest.php
new file mode 100644
index 00000000..4e211301
--- /dev/null
+++ b/tests/Controller/AuthorizationTest.php
@@ -0,0 +1,222 @@
+.
+ */
+
+namespace App\Tests\Controller;
+
+use App\Entity\UserSystem\User;
+use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use Symfony\Bundle\FrameworkBundle\KernelBrowser;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * Verifies the HTTP access-control boundaries:
+ *
+ * The app has an "anonymous" fixture user with readonly permissions, so truly
+ * public read routes return 200 even without a session.  Write-protected routes
+ * return 401 for unauthenticated requests (not a 302 redirect).
+ *
+ * Users: admin (all-allow), user (editor preset), noread (no group/no perms)
+ */
+#[Group('DB')]
+#[Group('slow')]
+final class AuthorizationTest extends WebTestCase
+{
+    // -----------------------------------------------------------------------
+    // Data providers
+    // -----------------------------------------------------------------------
+
+    /**
+     * Routes readable by the anonymous user — unauthenticated requests get 200.
+     */
+    public static function publicReadRoutesProvider(): \Generator
+    {
+        yield 'homepage'        => ['/en/'];
+        yield 'part view'       => ['/en/part/1'];
+        yield 'statistics'      => ['/en/statistics'];
+        yield 'select category' => ['/en/select_api/category'];
+        yield 'typeahead tags'  => ['/en/typeahead/tags/search/test'];
+    }
+
+    /**
+     * Write-protected routes — unauthenticated gets 401 (not 302).
+     */
+    public static function writeProtectedRoutesProvider(): \Generator
+    {
+        yield 'part edit'    => ['/en/part/1/edit'];
+        yield 'part new'     => ['/en/part/new'];
+        yield 'user edit'    => ['/en/user/1/edit'];
+        yield 'log list'     => ['/en/log/'];
+        yield 'server info'  => ['/en/tools/server_infos'];
+    }
+
+    /**
+     * Routes the `noread` user (no group = no permissions) must be denied.
+     */
+    public static function noreadDeniedRoutesProvider(): \Generator
+    {
+        yield 'part view'       => ['/en/part/1'];
+        yield 'part edit'       => ['/en/part/1/edit'];
+        yield 'part new'        => ['/en/part/new'];
+        yield 'log list'        => ['/en/log/'];
+        yield 'server info'     => ['/en/tools/server_infos'];
+        yield 'select category' => ['/en/select_api/category'];
+        yield 'typeahead tags'  => ['/en/typeahead/tags/search/test'];
+    }
+
+    /**
+     * Routes the `user` (editor preset) must have access to.
+     */
+    public static function editorAllowedRoutesProvider(): \Generator
+    {
+        yield 'homepage'     => ['/en/'];
+        yield 'part view'    => ['/en/part/1'];
+        yield 'part edit'    => ['/en/part/1/edit'];
+        yield 'part new'     => ['/en/part/new'];
+        yield 'select cat'   => ['/en/select_api/category'];
+        yield 'typeahead'    => ['/en/typeahead/tags/search/test'];
+    }
+
+    /**
+     * Admin-only routes the `user` (editor) must be denied.
+     */
+    public static function editorDeniedRoutesProvider(): \Generator
+    {
+        yield 'user edit'   => ['/en/user/1/edit'];
+        yield 'log list'    => ['/en/log/'];
+        yield 'server info' => ['/en/tools/server_infos'];
+    }
+
+    /**
+     * Routes the `admin` user must be able to reach.
+     */
+    public static function adminAllowedRoutesProvider(): \Generator
+    {
+        yield 'user edit'   => ['/en/user/1/edit'];
+        yield 'log list'    => ['/en/log/'];
+        yield 'server info' => ['/en/tools/server_infos'];
+        yield 'part view'   => ['/en/part/1'];
+        yield 'part edit'   => ['/en/part/1/edit'];
+        yield 'statistics'  => ['/en/statistics'];
+    }
+
+    // -----------------------------------------------------------------------
+    // Helpers
+    // -----------------------------------------------------------------------
+
+    private function loginAs(string $username): KernelBrowser
+    {
+        $client = static::createClient();
+        $em = static::getContainer()->get(EntityManagerInterface::class);
+        $user = $em->getRepository(User::class)->findOneBy(['name' => $username]);
+        if ($user === null) {
+            $this->markTestSkipped("Fixture user '$username' not found.");
+        }
+        $client->loginUser($user);
+        $client->followRedirects(false);
+        return $client;
+    }
+
+    private function assertDenied(KernelBrowser $client, string $url): void
+    {
+        $client->request('GET', $url);
+        $code = $client->getResponse()->getStatusCode();
+        $this->assertTrue(
+            $code === Response::HTTP_FORBIDDEN || $code === Response::HTTP_UNAUTHORIZED || $client->getResponse()->isRedirect(),
+            "Expected 401/403/redirect on $url, got $code"
+        );
+    }
+
+    // -----------------------------------------------------------------------
+    // Unauthenticated: public reads
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('publicReadRoutesProvider')]
+    public function testUnauthenticatedCanReadPublicRoutes(string $url): void
+    {
+        $client = static::createClient();
+        $client->request('GET', $url);
+        // Anonymous user (readonly group) can access read-only content
+        $this->assertResponseIsSuccessful();
+    }
+
+    // -----------------------------------------------------------------------
+    // Unauthenticated: write routes → 401
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('writeProtectedRoutesProvider')]
+    public function testUnauthenticatedIsUnauthorizedOnWriteRoutes(string $url): void
+    {
+        $client = static::createClient();
+        $client->followRedirects(false);
+        $client->request('GET', $url);
+
+        $code = $client->getResponse()->getStatusCode();
+        $this->assertTrue(
+            $code === Response::HTTP_UNAUTHORIZED || $client->getResponse()->isRedirect(),
+            "Expected 401 or redirect on $url for unauthenticated request, got $code"
+        );
+    }
+
+    // -----------------------------------------------------------------------
+    // noread user: denied everywhere
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('noreadDeniedRoutesProvider')]
+    public function testNoreadUserIsDenied(string $url): void
+    {
+        $this->assertDenied($this->loginAs('noread'), $url);
+    }
+
+    // -----------------------------------------------------------------------
+    // Editor user
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('editorAllowedRoutesProvider')]
+    public function testEditorCanAccess(string $url): void
+    {
+        $client = $this->loginAs('user');
+        $client->request('GET', $url);
+        $this->assertResponseIsSuccessful();
+    }
+
+    #[DataProvider('editorDeniedRoutesProvider')]
+    public function testEditorIsDeniedOnAdminRoutes(string $url): void
+    {
+        $this->assertDenied($this->loginAs('user'), $url);
+    }
+
+    // -----------------------------------------------------------------------
+    // Admin user: can access everything
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('adminAllowedRoutesProvider')]
+    public function testAdminCanAccessAllRoutes(string $url): void
+    {
+        $client = $this->loginAs('admin');
+        $client->request('GET', $url);
+        $this->assertResponseIsSuccessful();
+    }
+}
diff --git a/tests/Controller/SelectApiControllerTest.php b/tests/Controller/SelectApiControllerTest.php
new file mode 100644
index 00000000..b07053b9
--- /dev/null
+++ b/tests/Controller/SelectApiControllerTest.php
@@ -0,0 +1,152 @@
+.
+ */
+
+namespace App\Tests\Controller;
+
+use App\Entity\UserSystem\User;
+use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use Symfony\Bundle\FrameworkBundle\KernelBrowser;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+
+/**
+ * Tests the SelectAPIController endpoints used by select2 widgets.
+ * These JSON endpoints back every structural-entity dropdown in the UI.
+ */
+#[Group('DB')]
+#[Group('slow')]
+final class SelectApiControllerTest extends WebTestCase
+{
+    public static function endpointProvider(): \Generator
+    {
+        yield 'category'         => ['/en/select_api/category'];
+        yield 'footprint'        => ['/en/select_api/footprint'];
+        yield 'manufacturer'     => ['/en/select_api/manufacturer'];
+        yield 'measurement_unit' => ['/en/select_api/measurement_unit'];
+        yield 'project'          => ['/en/select_api/project'];
+        yield 'storage_location' => ['/en/select_api/storage_location'];
+        yield 'label_profiles'   => ['/en/select_api/label_profiles'];
+    }
+
+    private function adminClient(): KernelBrowser
+    {
+        $client = static::createClient();
+        $em = static::getContainer()->get(EntityManagerInterface::class);
+        $admin = $em->getRepository(User::class)->findOneBy(['name' => 'admin']);
+        if ($admin === null) {
+            $this->markTestSkipped('Fixture user admin not found.');
+        }
+        $client->loginUser($admin);
+        return $client;
+    }
+
+    // -----------------------------------------------------------------------
+    // Response format
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('endpointProvider')]
+    public function testEndpointReturns200WithJsonContentType(string $url): void
+    {
+        $client = $this->adminClient();
+        $client->request('GET', $url);
+
+        $this->assertResponseIsSuccessful();
+        $this->assertResponseHeaderSame('content-type', 'application/json');
+    }
+
+    #[DataProvider('endpointProvider')]
+    public function testEndpointReturnsValidJsonArray(string $url): void
+    {
+        $client = $this->adminClient();
+        $client->request('GET', $url);
+
+        $body = $client->getResponse()->getContent();
+        $decoded = json_decode($body, true);
+
+        $this->assertIsArray($decoded, "Response from $url is not a valid JSON array");
+    }
+
+    #[DataProvider('endpointProvider')]
+    public function testEachEntryHasTextAndValueKeys(string $url): void
+    {
+        $client = $this->adminClient();
+        $client->request('GET', $url);
+
+        $decoded = json_decode($client->getResponse()->getContent(), true);
+        // Some endpoints include an empty "select none" entry at index 0; all entries must have text + value
+        foreach ($decoded as $entry) {
+            $this->assertArrayHasKey('text', $entry, "Entry in $url missing 'text' key");
+            $this->assertArrayHasKey('value', $entry, "Entry in $url missing 'value' key");
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    // Access control
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('endpointProvider')]
+    public function testUnauthenticatedCanReadSelectApi(string $url): void
+    {
+        // The anonymous user (readonly group) has read access to structural entities,
+        // so these endpoints return 200 even without a session.
+        $client = static::createClient();
+        $client->request('GET', $url);
+        $this->assertResponseIsSuccessful();
+    }
+
+    #[DataProvider('endpointProvider')]
+    public function testNoreadUserIsDenied(string $url): void
+    {
+        $client = static::createClient();
+        $em = static::getContainer()->get(EntityManagerInterface::class);
+        $noread = $em->getRepository(User::class)->findOneBy(['name' => 'noread']);
+        if ($noread === null) {
+            $this->markTestSkipped('Fixture user noread not found.');
+        }
+        $client->loginUser($noread);
+        $client->followRedirects(false);
+        $client->request('GET', $url);
+
+        $response = $client->getResponse();
+        $this->assertTrue(
+            $response->getStatusCode() === 403 || $response->isRedirect(),
+            "Expected 403 or redirect for noread user on $url, got " . $response->getStatusCode()
+        );
+    }
+
+    #[DataProvider('endpointProvider')]
+    public function testEditorUserCanAccess(string $url): void
+    {
+        $client = static::createClient();
+        $em = static::getContainer()->get(EntityManagerInterface::class);
+        $user = $em->getRepository(User::class)->findOneBy(['name' => 'user']);
+        if ($user === null) {
+            $this->markTestSkipped('Fixture user user not found.');
+        }
+        $client->loginUser($user);
+        $client->request('GET', $url);
+
+        $this->assertResponseIsSuccessful();
+    }
+}
diff --git a/tests/Controller/TypeaheadControllerTest.php b/tests/Controller/TypeaheadControllerTest.php
new file mode 100644
index 00000000..ce2747fa
--- /dev/null
+++ b/tests/Controller/TypeaheadControllerTest.php
@@ -0,0 +1,162 @@
+.
+ */
+
+namespace App\Tests\Controller;
+
+use App\Entity\UserSystem\User;
+use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use Symfony\Bundle\FrameworkBundle\KernelBrowser;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+
+/**
+ * Tests the TypeaheadController JSON endpoints that back autocomplete widgets in the UI.
+ */
+#[Group('DB')]
+#[Group('slow')]
+final class TypeaheadControllerTest extends WebTestCase
+{
+    public static function endpointProvider(): \Generator
+    {
+        yield 'tags search'                => ['/en/typeahead/tags/search/test'];
+        yield 'parameters part search'     => ['/en/typeahead/parameters/part/search/voltage'];
+        yield 'parameters category search' => ['/en/typeahead/parameters/category/search/NPN'];
+        yield 'builtin resources'          => ['/en/typeahead/builtInResources/search?query=DIP'];
+        yield 'parts search'               => ['/en/typeahead/parts/search/res'];
+    }
+
+    public static function partsReadEndpointProvider(): \Generator
+    {
+        // These require @parts.read — noread user must be denied
+        yield 'tags search'            => ['/en/typeahead/tags/search/test'];
+        yield 'parameters part search' => ['/en/typeahead/parameters/part/search/voltage'];
+        yield 'parts search'           => ['/en/typeahead/parts/search/res'];
+    }
+
+    private function loginClient(string $username): KernelBrowser
+    {
+        $client = static::createClient();
+        $em = static::getContainer()->get(EntityManagerInterface::class);
+        $user = $em->getRepository(User::class)->findOneBy(['name' => $username]);
+        if ($user === null) {
+            $this->markTestSkipped("Fixture user '$username' not found.");
+        }
+        $client->loginUser($user);
+        return $client;
+    }
+
+    // -----------------------------------------------------------------------
+    // Response format
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('endpointProvider')]
+    public function testEndpointReturnsSuccessfulJsonForAdmin(string $url): void
+    {
+        $client = $this->loginClient('admin');
+        $client->request('GET', $url);
+
+        $this->assertResponseIsSuccessful();
+        $this->assertJson($client->getResponse()->getContent());
+    }
+
+    #[DataProvider('endpointProvider')]
+    public function testEndpointReturnsJsonArray(string $url): void
+    {
+        $client = $this->loginClient('admin');
+        $client->request('GET', $url);
+
+        $decoded = json_decode($client->getResponse()->getContent(), true);
+        $this->assertIsArray($decoded, "Response from $url should be a JSON array");
+    }
+
+    // -----------------------------------------------------------------------
+    // Tags search: result structure
+    // -----------------------------------------------------------------------
+
+    public function testTagsSearchReturnsStrings(): void
+    {
+        $client = $this->loginClient('admin');
+        $client->request('GET', '/en/typeahead/tags/search/a');
+
+        $tags = json_decode($client->getResponse()->getContent(), true);
+        $this->assertIsArray($tags);
+        foreach ($tags as $tag) {
+            $this->assertIsString($tag, 'Each tag entry should be a plain string');
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    // Parts search: result structure
+    // -----------------------------------------------------------------------
+
+    public function testPartsSearchReturnsArrayWithExpectedKeys(): void
+    {
+        $client = $this->loginClient('admin');
+        $client->request('GET', '/en/typeahead/parts/search/test');
+
+        $parts = json_decode($client->getResponse()->getContent(), true);
+        $this->assertIsArray($parts);
+        // Each result must have at least id and name
+        foreach ($parts as $part) {
+            $this->assertArrayHasKey('id', $part);
+            $this->assertArrayHasKey('name', $part);
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    // Access control
+    // -----------------------------------------------------------------------
+
+    #[DataProvider('endpointProvider')]
+    public function testUnauthenticatedCanAccessTypeahead(string $url): void
+    {
+        // Anonymous user (readonly group) has @parts.read, so these endpoints return 200.
+        $client = static::createClient();
+        $client->request('GET', $url);
+        $this->assertResponseIsSuccessful();
+    }
+
+    #[DataProvider('partsReadEndpointProvider')]
+    public function testNoreadUserIsDenied(string $url): void
+    {
+        $client = $this->loginClient('noread');
+        $client->followRedirects(false);
+        $client->request('GET', $url);
+
+        $response = $client->getResponse();
+        $this->assertTrue(
+            $response->getStatusCode() === 403 || $response->isRedirect(),
+            "Expected 403 or redirect for noread user on $url, got " . $response->getStatusCode()
+        );
+    }
+
+    #[DataProvider('endpointProvider')]
+    public function testEditorUserCanAccess(string $url): void
+    {
+        $client = $this->loginClient('user');
+        $client->request('GET', $url);
+
+        $this->assertResponseIsSuccessful();
+    }
+}
diff --git a/tests/EventSubscriber/MaintenanceModeSubscriberTest.php b/tests/EventSubscriber/MaintenanceModeSubscriberTest.php
new file mode 100644
index 00000000..0d975ee0
--- /dev/null
+++ b/tests/EventSubscriber/MaintenanceModeSubscriberTest.php
@@ -0,0 +1,103 @@
+.
+ */
+
+namespace App\Tests\EventSubscriber;
+
+use App\EventSubscriber\MaintenanceModeSubscriber;
+use App\Services\System\UpdateExecutor;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Event\RequestEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+final class MaintenanceModeSubscriberTest extends TestCase
+{
+    private function makeSubscriber(bool $maintenanceActive): MaintenanceModeSubscriber
+    {
+        $executor = $this->createMock(UpdateExecutor::class);
+        $executor->method('isMaintenanceMode')->willReturn($maintenanceActive);
+        $executor->method('getMaintenanceInfo')->willReturn(
+            $maintenanceActive ? ['reason' => 'Test update', 'enabled_at' => date('Y-m-d H:i:s')] : null
+        );
+        return new MaintenanceModeSubscriber($executor);
+    }
+
+    private function makeEvent(string $url = 'http://example.com/'): RequestEvent
+    {
+        $kernel = $this->createMock(HttpKernelInterface::class);
+        $request = Request::create($url);
+        return new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
+    }
+
+    public function testNoMaintenanceModeDoesNotSetResponse(): void
+    {
+        $subscriber = $this->makeSubscriber(false);
+        $event = $this->makeEvent();
+
+        $subscriber->onKernelRequest($event);
+
+        // When not in maintenance mode, no response is ever set regardless of SAPI
+        $this->assertFalse($event->hasResponse());
+    }
+
+    public function testCliRequestIsNeverBlocked(): void
+    {
+        // Tests run from CLI (PHP_SAPI === 'cli'), so maintenance mode never blocks CLI requests.
+        // This verifies the intentional behaviour: maintenance mode only affects web requests.
+        $subscriber = $this->makeSubscriber(true);
+        $event = $this->makeEvent();
+
+        $subscriber->onKernelRequest($event);
+
+        // CLI requests pass through even with maintenance active
+        $this->assertFalse($event->hasResponse());
+    }
+
+    public function testSubRequestIsIgnored(): void
+    {
+        $subscriber = $this->makeSubscriber(true);
+        $kernel = $this->createMock(HttpKernelInterface::class);
+        $request = Request::create('http://example.com/');
+        $event = new RequestEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST);
+
+        $subscriber->onKernelRequest($event);
+
+        $this->assertFalse($event->hasResponse());
+    }
+
+    public function testSubscriberListensToKernelRequest(): void
+    {
+        $events = MaintenanceModeSubscriber::getSubscribedEvents();
+        $this->assertArrayHasKey(KernelEvents::REQUEST, $events);
+    }
+
+    public function testSubscriberListensWithHighPriority(): void
+    {
+        $events = MaintenanceModeSubscriber::getSubscribedEvents();
+        $config = $events[KernelEvents::REQUEST];
+        // Config is ['methodName', priority]
+        $priority = is_array($config) ? (int) ($config[1] ?? 0) : 0;
+        $this->assertGreaterThan(0, $priority, 'Maintenance subscriber should run with high priority');
+    }
+}
diff --git a/tests/EventSubscriber/RedirectToHttpsSubscriberTest.php b/tests/EventSubscriber/RedirectToHttpsSubscriberTest.php
new file mode 100644
index 00000000..ec782b66
--- /dev/null
+++ b/tests/EventSubscriber/RedirectToHttpsSubscriberTest.php
@@ -0,0 +1,101 @@
+.
+ */
+
+namespace App\Tests\EventSubscriber;
+
+use App\EventSubscriber\RedirectToHttpsSubscriber;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Event\RequestEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\Security\Http\HttpUtils;
+
+final class RedirectToHttpsSubscriberTest extends TestCase
+{
+    private function makeEvent(string $url, bool $isMainRequest = true): RequestEvent
+    {
+        $kernel = $this->createMock(HttpKernelInterface::class);
+        $request = Request::create($url);
+        return new RequestEvent($kernel, $request, $isMainRequest ? HttpKernelInterface::MAIN_REQUEST : HttpKernelInterface::SUB_REQUEST);
+    }
+
+    public function testHttpRequestIsRedirectedToHttpsWhenEnabled(): void
+    {
+        $subscriber = new RedirectToHttpsSubscriber(true, new HttpUtils());
+        $event = $this->makeEvent('http://example.com/some/path');
+
+        $subscriber->onKernelRequest($event);
+
+        $this->assertTrue($event->hasResponse());
+        $response = $event->getResponse();
+        $this->assertStringStartsWith('https://', $response->getTargetUrl());
+    }
+
+    public function testHttpsRequestIsNotRedirectedWhenEnabled(): void
+    {
+        $subscriber = new RedirectToHttpsSubscriber(true, new HttpUtils());
+        $event = $this->makeEvent('https://example.com/some/path');
+
+        $subscriber->onKernelRequest($event);
+
+        $this->assertFalse($event->hasResponse());
+    }
+
+    public function testHttpRequestIsNotRedirectedWhenDisabled(): void
+    {
+        $subscriber = new RedirectToHttpsSubscriber(false, new HttpUtils());
+        $event = $this->makeEvent('http://example.com/some/path');
+
+        $subscriber->onKernelRequest($event);
+
+        $this->assertFalse($event->hasResponse());
+    }
+
+    public function testSubRequestIsNotRedirected(): void
+    {
+        $subscriber = new RedirectToHttpsSubscriber(true, new HttpUtils());
+        $event = $this->makeEvent('http://example.com/', false);
+
+        $subscriber->onKernelRequest($event);
+
+        $this->assertFalse($event->hasResponse());
+    }
+
+    public function testRedirectUrlPreservesPath(): void
+    {
+        $subscriber = new RedirectToHttpsSubscriber(true, new HttpUtils());
+        $event = $this->makeEvent('http://example.com/admin/parts?q=test');
+
+        $subscriber->onKernelRequest($event);
+
+        $this->assertTrue($event->hasResponse());
+        $this->assertStringContainsString('/admin/parts', $event->getResponse()->getTargetUrl());
+        $this->assertStringContainsString('q=test', $event->getResponse()->getTargetUrl());
+    }
+
+    public function testSubscriberListensToKernelRequestEvent(): void
+    {
+        $events = RedirectToHttpsSubscriber::getSubscribedEvents();
+        $this->assertArrayHasKey('kernel.request', $events);
+    }
+}
diff --git a/tests/Services/Cache/ElementCacheTagGeneratorTest.php b/tests/Services/Cache/ElementCacheTagGeneratorTest.php
new file mode 100644
index 00000000..f747441f
--- /dev/null
+++ b/tests/Services/Cache/ElementCacheTagGeneratorTest.php
@@ -0,0 +1,67 @@
+.
+ */
+
+namespace App\Tests\Services\Cache;
+
+use App\Entity\Parts\Part;
+use App\Services\Cache\ElementCacheTagGenerator;
+use PHPUnit\Framework\TestCase;
+
+final class ElementCacheTagGeneratorTest extends TestCase
+{
+    private ElementCacheTagGenerator $service;
+
+    protected function setUp(): void
+    {
+        $this->service = new ElementCacheTagGenerator();
+    }
+
+    public function testClassNameIsConvertedToTag(): void
+    {
+        $tag = $this->service->getElementTypeCacheTag(Part::class);
+        // Backslashes must be replaced by underscores
+        $this->assertStringNotContainsString('\\', $tag);
+        $this->assertSame(str_replace('\\', '_', Part::class), $tag);
+    }
+
+    public function testObjectInputGivesSameResultAsClassName(): void
+    {
+        $part = new Part();
+        $tagFromObject = $this->service->getElementTypeCacheTag($part);
+        $tagFromClass = $this->service->getElementTypeCacheTag(Part::class);
+        $this->assertSame($tagFromClass, $tagFromObject);
+    }
+
+    public function testResultIsCached(): void
+    {
+        $tag1 = $this->service->getElementTypeCacheTag(Part::class);
+        $tag2 = $this->service->getElementTypeCacheTag(Part::class);
+        $this->assertSame($tag1, $tag2);
+    }
+
+    public function testNonExistentClassThrowsException(): void
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->service->getElementTypeCacheTag('App\\NonExistent\\Foo');
+    }
+}
diff --git a/tests/Services/Cache/UserCacheKeyGeneratorTest.php b/tests/Services/Cache/UserCacheKeyGeneratorTest.php
new file mode 100644
index 00000000..23583db4
--- /dev/null
+++ b/tests/Services/Cache/UserCacheKeyGeneratorTest.php
@@ -0,0 +1,110 @@
+.
+ */
+
+namespace App\Tests\Services\Cache;
+
+use App\Entity\UserSystem\User;
+use App\Services\Cache\UserCacheKeyGenerator;
+use PHPUnit\Framework\TestCase;
+use Symfony\Bundle\SecurityBundle\Security;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+final class UserCacheKeyGeneratorTest extends TestCase
+{
+    private function makeGenerator(?User $loggedInUser, ?Request $request = null): UserCacheKeyGenerator
+    {
+        $security = $this->createMock(Security::class);
+        $security->method('getUser')->willReturn($loggedInUser);
+
+        $requestStack = $this->createMock(RequestStack::class);
+        $requestStack->method('getCurrentRequest')->willReturn($request);
+
+        return new UserCacheKeyGenerator($security, $requestStack);
+    }
+
+    private function makeUserWithId(int $id): User
+    {
+        $user = new User();
+        $ref = new \ReflectionProperty(User::class, 'id');
+        $ref->setValue($user, $id);
+        return $user;
+    }
+
+    public function testAnonymousUserKeyContainsAnonymousId(): void
+    {
+        $service = $this->makeGenerator(null);
+        $key = $service->generateKey();
+        $this->assertStringContainsString((string) User::ID_ANONYMOUS, $key);
+    }
+
+    public function testExplicitAnonymousUserGivesSameKeyAsNull(): void
+    {
+        $anonUser = $this->makeUserWithId(User::ID_ANONYMOUS);
+        $anonUser->setName('anonymous');
+
+        $service = $this->makeGenerator(null);
+        $keyFromNull = $service->generateKey(null);
+        $keyFromAnon = $service->generateKey($anonUser);
+        $this->assertSame($keyFromNull, $keyFromAnon);
+    }
+
+    public function testKeyForRealUserContainsUserId(): void
+    {
+        $user = $this->makeUserWithId(42);
+        $service = $this->makeGenerator(null);
+
+        $key = $service->generateKey($user);
+        $this->assertStringContainsString('42', $key);
+        $this->assertStringNotContainsString((string) User::ID_ANONYMOUS, $key);
+    }
+
+    public function testLocaleFromRequestIsIncludedInKey(): void
+    {
+        $request = Request::create('/');
+        $request->setLocale('de');
+
+        $service = $this->makeGenerator(null, $request);
+        $key = $service->generateKey();
+        $this->assertStringContainsString('de', $key);
+    }
+
+    public function testDifferentUsersProduceDifferentKeys(): void
+    {
+        $service = $this->makeGenerator(null);
+
+        $user1 = $this->makeUserWithId(10);
+        $user2 = $this->makeUserWithId(20);
+
+        $this->assertNotSame($service->generateKey($user1), $service->generateKey($user2));
+    }
+
+    public function testCurrentlyLoggedInUserIsUsedWhenNoExplicitUser(): void
+    {
+        $loggedIn = $this->makeUserWithId(99);
+        $service = $this->makeGenerator($loggedIn);
+
+        $key = $service->generateKey();
+        $this->assertStringContainsString('99', $key);
+    }
+}
diff --git a/tests/Services/EntityURLGeneratorTest.php b/tests/Services/EntityURLGeneratorTest.php
new file mode 100644
index 00000000..f21511e0
--- /dev/null
+++ b/tests/Services/EntityURLGeneratorTest.php
@@ -0,0 +1,113 @@
+.
+ */
+
+namespace App\Tests\Services;
+
+use App\Entity\Base\AbstractDBElement;
+use App\Entity\Parts\Category;
+use App\Entity\Parts\Footprint;
+use App\Entity\Parts\Manufacturer;
+use App\Entity\Parts\Part;
+use App\Entity\Parts\StorageLocation;
+use App\Entity\Parts\Supplier;
+use App\Entity\UserSystem\User;
+use App\Exceptions\EntityNotSupportedException;
+use App\Services\EntityURLGenerator;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+
+final class EntityURLGeneratorTest extends WebTestCase
+{
+    private static EntityURLGenerator $service;
+
+    public static function setUpBeforeClass(): void
+    {
+        self::bootKernel();
+        self::$service = self::getContainer()->get(EntityURLGenerator::class);
+    }
+
+    private function entityWithId(string $class, int $id): AbstractDBElement
+    {
+        $entity = new $class();
+        $ref = new \ReflectionProperty(AbstractDBElement::class, 'id');
+        $ref->setValue($entity, $id);
+        return $entity;
+    }
+
+    public function testInfoUrlForPartContainsPartPath(): void
+    {
+        $part = $this->entityWithId(Part::class, 1);
+        $url = self::$service->infoURL($part);
+        $this->assertStringContainsString('part', $url);
+        $this->assertStringContainsString('1', $url);
+    }
+
+    public function testEditUrlForCategoryContainsCategoryPath(): void
+    {
+        $category = $this->entityWithId(Category::class, 5);
+        $url = self::$service->editURL($category);
+        $this->assertStringContainsString('category', $url);
+        $this->assertStringContainsString('5', $url);
+    }
+
+    public function testListPartsUrlForSupplierContainsSupplierPath(): void
+    {
+        $supplier = $this->entityWithId(Supplier::class, 7);
+        $url = self::$service->listPartsURL($supplier);
+        $this->assertStringContainsString('supplier', $url);
+    }
+
+    public function testGetUrlWithInfoTypeCallsInfoUrl(): void
+    {
+        $part = $this->entityWithId(Part::class, 3);
+        $url = self::$service->getURL($part, 'info');
+        $this->assertStringContainsString('part', $url);
+    }
+
+    public function testGetUrlWithEditTypeCallsEditUrl(): void
+    {
+        $manufacturer = $this->entityWithId(Manufacturer::class, 2);
+        $url = self::$service->getURL($manufacturer, 'edit');
+        $this->assertStringContainsString('manufacturer', $url);
+    }
+
+    public function testGetUrlWithUnknownTypeThrowsException(): void
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $part = $this->entityWithId(Part::class, 1);
+        self::$service->getURL($part, 'unsupported_type');
+    }
+
+    public function testInfoUrlForUserContainsUserPath(): void
+    {
+        $user = $this->entityWithId(User::class, 10);
+        $url = self::$service->editURL($user);
+        $this->assertStringContainsString('user', $url);
+    }
+
+    public function testListPartsUrlForStorelocationContainsStorelocationPath(): void
+    {
+        $loc = $this->entityWithId(StorageLocation::class, 4);
+        $url = self::$service->listPartsURL($loc);
+        $this->assertStringContainsString('store', $url);
+    }
+}
diff --git a/tests/Services/Formatters/MarkdownParserTest.php b/tests/Services/Formatters/MarkdownParserTest.php
new file mode 100644
index 00000000..0b27972f
--- /dev/null
+++ b/tests/Services/Formatters/MarkdownParserTest.php
@@ -0,0 +1,86 @@
+.
+ */
+
+namespace App\Tests\Services\Formatters;
+
+use App\Services\Formatters\MarkdownParser;
+use PHPUnit\Framework\TestCase;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+final class MarkdownParserTest extends TestCase
+{
+    private MarkdownParser $service;
+
+    protected function setUp(): void
+    {
+        $translator = $this->createMock(TranslatorInterface::class);
+        $translator->method('trans')->willReturn('Loading...');
+        $this->service = new MarkdownParser($translator);
+    }
+
+    public function testOutputContainsDataMarkdownAttribute(): void
+    {
+        $result = $this->service->markForRendering('**hello**');
+        $this->assertStringContainsString('data-markdown=', $result);
+        $this->assertStringContainsString('data-controller="common--markdown"', $result);
+    }
+
+    public function testMarkdownContentIsHtmlescapedInAttribute(): void
+    {
+        $result = $this->service->markForRendering('');
+        // The raw < should not appear unescaped inside the attribute
+        $this->assertStringNotContainsString('