diff --git a/assets/tools/FlowReserve.js b/assets/tools/FlowReserve.js index 6052e09..d33474d 100644 --- a/assets/tools/FlowReserve.js +++ b/assets/tools/FlowReserve.js @@ -291,10 +291,50 @@ export class FlowReserve extends HTMLAnchorElement { ${this.formatPrice(total.totalTTC || total.totalHT)} - + Valider ma demande `; + + const validateBtn = footer.querySelector('#flow-validate-btn'); + if (validateBtn) { + validateBtn.addEventListener('click', (e) => { + this.validateBasket(e); + }); + } + } + + async validateBasket(e) { + e.preventDefault(); + + const ids = this.getList(); + let dates = { start: null, end: null }; + try { + dates = JSON.parse(localStorage.getItem('reservation_dates') || '{}'); + } catch (error) { + console.warn('Invalid reservation dates in localStorage'); + } + + try { + const response = await fetch('/reservation/session', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + ids, + start: dates.start, + end: dates.end + }) + }); + + if (!response.ok) throw new Error('Erreur réseau'); + + const data = await response.json(); + if (data.flowUrl) { + window.location.href = data.flowUrl; + } + } catch (error) { + console.error('Erreur lors de la validation du panier', error); + } } formatDate(dateString) { diff --git a/composer.json b/composer.json index df4e354..a2ce6be 100644 --- a/composer.json +++ b/composer.json @@ -12,28 +12,28 @@ "ext-zip": "*", "chillerlan/php-qrcode": ">=5.0.5", "cocur/slugify": ">=4.7.1", - "doctrine/dbal": "^3.10.4", - "doctrine/doctrine-bundle": "^2.18.2", + "doctrine/dbal": "^4.4.1", + "doctrine/doctrine-bundle": "^3.2.2", "doctrine/doctrine-migrations-bundle": "^3.7.0", - "doctrine/orm": "^3.6.1", + "doctrine/orm": "^3.6.2", "docusealco/docuseal-php": "^1.0.5", - "endroid/qr-code": "^6.0.9", + "endroid/qr-code": "^6.1.0", "exbil/mailcow-php-api": ">=0.15.0", - "fkrzski/robots-txt": "^2.0", - "fpdf/fpdf": "^1.86", - "gemini-api-php/client": "^1.7", + "fkrzski/robots-txt": "^2.1", + "fpdf/fpdf": "^1.86.1", + "gemini-api-php/client": "^1.7.2", "google/apiclient": "^2.19.0", "google/cloud": "^0.296.0", "healey/robots": "^1.0.1", "imagine/imagine": "^1.5.2", "io-developer/php-whois": ">=4.1.10", - "jaybizzle/crawler-detect": "^1.3", + "jaybizzle/crawler-detect": "^1.3.6", "knplabs/knp-paginator-bundle": "^6.10", "knpuniversity/oauth2-client-bundle": "^2.20.1", "lasserafn/php-initial-avatar-generator": "^4.5", - "league/flysystem-aws-s3-v3": "^3.30.1", + "league/flysystem-aws-s3-v3": "^3.31.0", "league/flysystem-bundle": "^3.6.1", - "liip/imagine-bundle": "^2.15", + "liip/imagine-bundle": "^2.17.1", "lufiipe/insee-sierene": ">=1", "meilisearch/meilisearch-php": "^1.16.1", "minishlink/web-push": "^9.0.4", @@ -45,56 +45,55 @@ "pear/net_dns2": ">=2.0.7", "phpdocumentor/reflection-docblock": "^5.6.6", "phpoffice/phpspreadsheet": "^5.4", - "phpstan/phpdoc-parser": "^2.3.1", - "presta/sitemap-bundle": "^4.2", - "scheb/2fa-backup-code": "^7.13.1", - "scheb/2fa-bundle": "^7.13.1", - "scheb/2fa-email": "^7.13.1", - "scheb/2fa-google-authenticator": "^7.13.1", + "phpstan/phpdoc-parser": "^2.3.2", + "presta/sitemap-bundle": "^4.3", + "scheb/2fa-backup-code": "^8.3.0", + "scheb/2fa-bundle": "^8.3.0", + "scheb/2fa-email": "^8.3.0", + "scheb/2fa-google-authenticator": "^8.3.0", "sentry/sentry-symfony": "^5.8.3", "setasign/fpdi": "^2.6.4", - "spatie/mjml-php": "^1.2.5", - "spomky-labs/pwa-bundle": "1.3.5", - "spomky-labs/web-push-bundle": "^3.1.2", + "spomky-labs/pwa-bundle": "1.5.0", + "spomky-labs/web-push-bundle": "^3.2.1", "stancer/stancer": ">=2.0.1", "stevenmaguire/oauth2-keycloak": "^5.1", - "stripe/stripe-php": "^19.1", - "symfony/amazon-mailer": "7.3.*", - "symfony/asset": "7.3.*", - "symfony/asset-mapper": "7.3.*", - "symfony/console": "7.3.*", - "symfony/doctrine-messenger": "7.3.*", - "symfony/dotenv": "7.3.*", - "symfony/expression-language": "7.3.*", + "stripe/stripe-php": "^19.3", + "symfony/amazon-mailer": "8.0.*", + "symfony/asset": "8.0.*", + "symfony/asset-mapper": "8.0.*", + "symfony/console": "8.0.*", + "symfony/doctrine-messenger": "8.0.*", + "symfony/dotenv": "8.0.*", + "symfony/expression-language": "8.0.*", "symfony/flex": "^2.10.0", - "symfony/form": "7.3.*", - "symfony/framework-bundle": "7.3.*", - "symfony/http-client": "7.3.*", - "symfony/intl": "7.3.*", - "symfony/mailer": "7.3.*", - "symfony/mime": "7.3.*", - "symfony/monolog-bundle": "^3.11.1", - "symfony/notifier": "7.3.*", - "symfony/process": "7.3.*", - "symfony/property-access": "7.3.*", - "symfony/property-info": "7.3.*", - "symfony/redis-messenger": "7.3.*", - "symfony/runtime": "7.3.*", - "symfony/security-bundle": "7.3.*", - "symfony/serializer": "7.3.*", - "symfony/string": "7.3.*", - "symfony/translation": "7.3.*", - "symfony/twig-bundle": "7.3.*", - "symfony/uid": "7.3.*", - "symfony/validator": "7.3.*", - "symfony/web-link": "7.3.*", - "symfony/yaml": "7.3.*", + "symfony/form": "8.0.*", + "symfony/framework-bundle": "8.0.*", + "symfony/http-client": "8.0.*", + "symfony/intl": "8.0.*", + "symfony/mailer": "8.0.*", + "symfony/mime": "8.0.*", + "symfony/monolog-bundle": "^4.0.1", + "symfony/notifier": "8.0.*", + "symfony/process": "8.0.*", + "symfony/property-access": "8.0.*", + "symfony/property-info": "8.0.*", + "symfony/redis-messenger": "8.0.*", + "symfony/runtime": "8.0.*", + "symfony/security-bundle": "8.0.*", + "symfony/serializer": "8.0.*", + "symfony/string": "8.0.*", + "symfony/translation": "8.0.*", + "symfony/twig-bundle": "8.0.*", + "symfony/uid": "8.0.*", + "symfony/validator": "8.0.*", + "symfony/web-link": "8.0.*", + "symfony/yaml": "8.0.*", "tecnickcom/tcpdf": "^6.10.1", - "twig/extra-bundle": "^3.22.2", - "twig/intl-extra": "^3.22.1", - "twig/twig": "^3.22.2", + "twig/extra-bundle": "^3.23.0", + "twig/intl-extra": "^3.23.0", + "twig/twig": "^3.23.0", "vich/uploader-bundle": "^2.9.1", - "web-auth/webauthn-lib": ">=5.2.3", + "web-auth/webauthn-lib": "5.3.x-dev", "web-token/jwt-library": "^4.1.3" }, "config": { @@ -145,18 +144,18 @@ "extra": { "symfony": { "allow-contrib": true, - "require": "7.3.*" + "require": "8.0.*" } }, "require-dev": { "fakerphp/faker": "^1.24.1", - "phpunit/phpunit": "^12.5.5", - "rector/rector": "^2.3.1", - "symfony/browser-kit": "7.3.*", - "symfony/css-selector": "7.3.*", - "symfony/debug-bundle": "7.3.*", + "phpunit/phpunit": "^12.5.8", + "rector/rector": "^2.3.5", + "symfony/browser-kit": "8.0.*", + "symfony/css-selector": "8.0.*", + "symfony/debug-bundle": "8.0.*", "symfony/maker-bundle": "^1.65.1", - "symfony/stopwatch": "7.3.*", - "symfony/web-profiler-bundle": "7.3.*" + "symfony/stopwatch": "8.0.*", + "symfony/web-profiler-bundle": "8.0.*" } } diff --git a/composer.lock b/composer.lock index 2bfefb0..fdb70bf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "04441998f46efc5154a83945a7ca9a46", + "content-hash": "e87e0f4a157318bc4167a20dc3b5af2e", "packages": [ { "name": "async-aws/core", @@ -197,16 +197,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.369.19", + "version": "3.369.24", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "32fee3a25290186724ede9ca177d5090f7c5a837" + "reference": "17f404a47879c1fb47175ac2b61881ab0dc2dc5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/32fee3a25290186724ede9ca177d5090f7c5a837", - "reference": "32fee3a25290186724ede9ca177d5090f7c5a837", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/17f404a47879c1fb47175ac2b61881ab0dc2dc5c", + "reference": "17f404a47879c1fb47175ac2b61881ab0dc2dc5c", "shasum": "" }, "require": { @@ -288,9 +288,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.369.19" + "source": "https://github.com/aws/aws-sdk-php/tree/3.369.24" }, - "time": "2026-01-23T19:05:51+00:00" + "time": "2026-01-30T19:14:32+00:00" }, { "name": "bacon/bacon-qr-code", @@ -349,16 +349,16 @@ }, { "name": "brick/math", - "version": "0.14.1", + "version": "0.14.2", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0" + "reference": "55c950aa71a2cabc1d8f2bec1f8a7020bd244aa2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0", + "url": "https://api.github.com/repos/brick/math/zipball/55c950aa71a2cabc1d8f2bec1f8a7020bd244aa2", + "reference": "55c950aa71a2cabc1d8f2bec1f8a7020bd244aa2", "shasum": "" }, "require": { @@ -397,7 +397,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.1" + "source": "https://github.com/brick/math/tree/0.14.2" }, "funding": [ { @@ -405,30 +405,30 @@ "type": "github" } ], - "time": "2025-11-24T14:40:29+00:00" + "time": "2026-01-30T14:03:11+00:00" }, { "name": "carbonphp/carbon-doctrine-types", - "version": "2.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", - "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb" + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", - "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0" + "php": "^8.1" }, "conflict": { - "doctrine/dbal": "<3.7.0 || >=4.0.0" + "doctrine/dbal": "<4.0.0 || >=5.0.0" }, "require-dev": { - "doctrine/dbal": "^3.7.0", + "doctrine/dbal": "^4.0.0", "nesbot/carbon": "^2.71.0 || ^3.0.0", "phpunit/phpunit": "^10.3" }, @@ -458,7 +458,7 @@ ], "support": { "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", - "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0" + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" }, "funding": [ { @@ -474,7 +474,7 @@ "type": "tidelift" } ], - "time": "2023-12-11T17:09:12+00:00" + "time": "2024-02-09T16:56:22+00:00" }, { "name": "chillerlan/php-qrcode", @@ -1075,48 +1075,40 @@ }, { "name": "doctrine/dbal", - "version": "3.10.4", + "version": "4.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868" + "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/63a46cb5aa6f60991186cc98c1d1b50c09311868", - "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c", + "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/deprecations": "^0.5.3|^1", - "doctrine/event-manager": "^1|^2", - "php": "^7.4 || ^8.0", + "doctrine/deprecations": "^1.1.5", + "php": "^8.2", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, - "conflict": { - "doctrine/cache": "< 1.11" - }, "require-dev": { - "doctrine/cache": "^1.11|^2.0", "doctrine/coding-standard": "14.0.0", "fig/log-test": "^1", - "jetbrains/phpstorm-stubs": "2023.1", + "jetbrains/phpstorm-stubs": "2023.2", "phpstan/phpstan": "2.1.30", + "phpstan/phpstan-phpunit": "2.0.7", "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "9.6.29", + "phpunit/phpunit": "11.5.23", "slevomat/coding-standard": "8.24.0", "squizlabs/php_codesniffer": "4.0.0", - "symfony/cache": "^5.4|^6.0|^7.0|^8.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0|^8.0" + "symfony/cache": "^6.3.8|^7.0|^8.0", + "symfony/console": "^5.4|^6.3|^7.0|^8.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, - "bin": [ - "bin/doctrine-dbal" - ], "type": "library", "autoload": { "psr-4": { @@ -1169,7 +1161,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.10.4" + "source": "https://github.com/doctrine/dbal/tree/4.4.1" }, "funding": [ { @@ -1185,7 +1177,7 @@ "type": "tidelift" } ], - "time": "2025-11-29T10:46:08+00:00" + "time": "2025-12-04T10:11:03+00:00" }, { "name": "doctrine/deprecations", @@ -1237,63 +1229,57 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.18.2", + "version": "3.2.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546" + "reference": "af84173db6978c3d2688ea3bcf3a91720b0704ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/0ff098b29b8b3c68307c8987dcaed7fd829c6546", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/af84173db6978c3d2688ea3bcf3a91720b0704ce", + "reference": "af84173db6978c3d2688ea3bcf3a91720b0704ce", "shasum": "" }, "require": { - "doctrine/dbal": "^3.7.0 || ^4.0", + "doctrine/dbal": "^4.0", "doctrine/deprecations": "^1.0", - "doctrine/persistence": "^3.1 || ^4", + "doctrine/persistence": "^4", "doctrine/sql-formatter": "^1.0.1", - "php": "^8.1", - "symfony/cache": "^6.4 || ^7.0", - "symfony/config": "^6.4 || ^7.0", - "symfony/console": "^6.4 || ^7.0", - "symfony/dependency-injection": "^6.4 || ^7.0", - "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3", - "symfony/framework-bundle": "^6.4 || ^7.0", - "symfony/service-contracts": "^2.5 || ^3" + "php": "^8.4", + "symfony/cache": "^6.4 || ^7.0 || ^8.0", + "symfony/config": "^6.4 || ^7.0 || ^8.0", + "symfony/console": "^6.4 || ^7.0 || ^8.0", + "symfony/dependency-injection": "^6.4 || ^7.0 || ^8.0", + "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3 || ^8.0", + "symfony/framework-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/service-contracts": "^3" }, "conflict": { - "doctrine/annotations": ">=3.0", - "doctrine/cache": "< 1.11", - "doctrine/orm": "<2.17 || >=4.0", - "symfony/var-exporter": "< 6.4.1 || 7.0.0", - "twig/twig": "<2.13 || >=3.0 <3.0.4" + "doctrine/orm": "<3.0 || >=4.0", + "twig/twig": "<3.0.4" }, "require-dev": { - "doctrine/annotations": "^1 || ^2", - "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^14", - "doctrine/orm": "^2.17 || ^3.1", - "friendsofphp/proxy-manager-lts": "^1.0", + "doctrine/orm": "^3.4.4", "phpstan/phpstan": "2.1.1", "phpstan/phpstan-phpunit": "2.0.3", "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "^10.5.53 || ^12.3.10", - "psr/log": "^1.1.4 || ^2.0 || ^3.0", - "symfony/doctrine-messenger": "^6.4 || ^7.0", - "symfony/expression-language": "^6.4 || ^7.0", - "symfony/messenger": "^6.4 || ^7.0", - "symfony/property-info": "^6.4 || ^7.0", - "symfony/security-bundle": "^6.4 || ^7.0", - "symfony/stopwatch": "^6.4 || ^7.0", - "symfony/string": "^6.4 || ^7.0", - "symfony/twig-bridge": "^6.4 || ^7.0", - "symfony/validator": "^6.4 || ^7.0", - "symfony/var-exporter": "^6.4.1 || ^7.0.1", - "symfony/web-profiler-bundle": "^6.4 || ^7.0", - "symfony/yaml": "^6.4 || ^7.0", - "twig/twig": "^2.14.7 || ^3.0.4" + "phpstan/phpstan-symfony": "^2.0", + "phpunit/phpunit": "^12.3.10", + "psr/log": "^3.0", + "symfony/doctrine-messenger": "^6.4 || ^7.0 || ^8.0", + "symfony/expression-language": "^6.4 || ^7.0 || ^8.0", + "symfony/messenger": "^6.4 || ^7.0 || ^8.0", + "symfony/property-info": "^6.4 || ^7.0 || ^8.0", + "symfony/security-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/stopwatch": "^6.4 || ^7.0 || ^8.0", + "symfony/string": "^6.4 || ^7.0 || ^8.0", + "symfony/twig-bridge": "^6.4 || ^7.0 || ^8.0", + "symfony/validator": "^6.4 || ^7.0 || ^8.0", + "symfony/web-profiler-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/yaml": "^6.4 || ^7.0 || ^8.0", + "twig/twig": "^3.21.1" }, "suggest": { "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", @@ -1338,7 +1324,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.18.2" + "source": "https://github.com/doctrine/DoctrineBundle/tree/3.2.2" }, "funding": [ { @@ -1354,7 +1340,7 @@ "type": "tidelift" } ], - "time": "2025-12-20T21:35:32+00:00" + "time": "2025-12-24T12:24:29+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -1443,16 +1429,16 @@ }, { "name": "doctrine/event-manager", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "c07799fcf5ad362050960a0fd068dded40b1e312" + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/c07799fcf5ad362050960a0fd068dded40b1e312", - "reference": "c07799fcf5ad362050960a0fd068dded40b1e312", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/dda33921b198841ca8dbad2eaa5d4d34769d18cf", + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf", "shasum": "" }, "require": { @@ -1514,7 +1500,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.1.0" + "source": "https://github.com/doctrine/event-manager/tree/2.1.1" }, "funding": [ { @@ -1530,7 +1516,7 @@ "type": "tidelift" } ], - "time": "2026-01-17T22:40:21+00:00" + "time": "2026-01-29T07:11:08+00:00" }, { "name": "doctrine/inflector", @@ -1873,16 +1859,16 @@ }, { "name": "doctrine/orm", - "version": "3.6.1", + "version": "3.6.2", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "2148940290e4c44b9101095707e71fb590832fa5" + "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/2148940290e4c44b9101095707e71fb590832fa5", - "reference": "2148940290e4c44b9101095707e71fb590832fa5", + "url": "https://api.github.com/repos/doctrine/orm/zipball/4262eb495b4d2a53b45de1ac58881e0091f2970f", + "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f", "shasum": "" }, "require": { @@ -1955,9 +1941,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.6.1" + "source": "https://github.com/doctrine/orm/tree/3.6.2" }, - "time": "2026-01-09T05:28:15+00:00" + "time": "2026-01-30T21:41:41+00:00" }, { "name": "doctrine/persistence", @@ -3638,16 +3624,16 @@ }, { "name": "google/protobuf", - "version": "v4.33.4", + "version": "v4.33.5", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "22d28025cda0d223a2e48c2e16c5284ecc9f5402" + "reference": "ebe8010a61b2ae0cff0d246fe1c4d44e9f7dfa6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/22d28025cda0d223a2e48c2e16c5284ecc9f5402", - "reference": "22d28025cda0d223a2e48c2e16c5284ecc9f5402", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/ebe8010a61b2ae0cff0d246fe1c4d44e9f7dfa6d", + "reference": "ebe8010a61b2ae0cff0d246fe1c4d44e9f7dfa6d", "shasum": "" }, "require": { @@ -3676,9 +3662,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.4" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.5" }, - "time": "2026-01-12T17:58:43+00:00" + "time": "2026-01-29T20:49:00+00:00" }, { "name": "grpc/grpc", @@ -4089,16 +4075,16 @@ }, { "name": "illuminate/collections", - "version": "v12.48.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "95eb9f848a02a05db35d71b63073ed5f09dc11ce" + "reference": "18ca56ad53265a18508198473b1523c1ad46edad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/95eb9f848a02a05db35d71b63073ed5f09dc11ce", - "reference": "95eb9f848a02a05db35d71b63073ed5f09dc11ce", + "url": "https://api.github.com/repos/illuminate/collections/zipball/18ca56ad53265a18508198473b1523c1ad46edad", + "reference": "18ca56ad53265a18508198473b1523c1ad46edad", "shasum": "" }, "require": { @@ -4145,11 +4131,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-19T15:23:52+00:00" + "time": "2026-01-23T16:02:04+00:00" }, { "name": "illuminate/conditionable", - "version": "v12.48.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -4195,7 +4181,7 @@ }, { "name": "illuminate/contracts", - "version": "v12.48.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -4243,7 +4229,7 @@ }, { "name": "illuminate/macroable", - "version": "v12.48.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -4289,7 +4275,7 @@ }, { "name": "illuminate/reflection", - "version": "v12.48.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/illuminate/reflection.git", @@ -4340,16 +4326,16 @@ }, { "name": "illuminate/support", - "version": "v12.48.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "da511879a72bad39bab776fee4e797a36ca3d681" + "reference": "196cae049b187ebffbe72efd22ef3ae57dd0a2db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/da511879a72bad39bab776fee4e797a36ca3d681", - "reference": "da511879a72bad39bab776fee4e797a36ca3d681", + "url": "https://api.github.com/repos/illuminate/support/zipball/196cae049b187ebffbe72efd22ef3ae57dd0a2db", + "reference": "196cae049b187ebffbe72efd22ef3ae57dd0a2db", "shasum": "" }, "require": { @@ -4416,7 +4402,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-19T15:23:13+00:00" + "time": "2026-01-27T02:58:23+00:00" }, { "name": "imagine/imagine", @@ -5567,29 +5553,30 @@ }, { "name": "liip/imagine-bundle", - "version": "2.15.0", + "version": "2.17.1", "source": { "type": "git", "url": "https://github.com/liip/LiipImagineBundle.git", - "reference": "f8c98a5a962806f26571db219412b64266c763d8" + "reference": "69d2df3c6606495d1878fa190d6c3dc4bc5623b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/liip/LiipImagineBundle/zipball/f8c98a5a962806f26571db219412b64266c763d8", - "reference": "f8c98a5a962806f26571db219412b64266c763d8", + "url": "https://api.github.com/repos/liip/LiipImagineBundle/zipball/69d2df3c6606495d1878fa190d6c3dc4bc5623b6", + "reference": "69d2df3c6606495d1878fa190d6c3dc4bc5623b6", "shasum": "" }, "require": { "ext-mbstring": "*", "imagine/imagine": "^1.3.2", - "php": "^7.2|^8.0", + "php": "^8.0", + "symfony/dependency-injection": "^5.4|^6.4|^7.4|^8.0", "symfony/deprecation-contracts": "^2.5 || ^3", - "symfony/filesystem": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/finder": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/framework-bundle": "^3.4.23|^4.4|^5.3|^6.0|^7.0", - "symfony/mime": "^4.4|^5.3|^6.0|^7.0", - "symfony/options-resolver": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/process": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.4|^7.3|^8.0", + "symfony/finder": "^5.4|^6.4|^7.3|^8.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.3|^8.0", + "symfony/mime": "^5.4|^6.4|^7.3|^8.0", + "symfony/options-resolver": "^5.4|^6.4|^7.3|^8.0", + "symfony/process": "^5.4|^6.4|^7.3|^8.0", "twig/twig": "^1.44|^2.9|^3.0" }, "require-dev": { @@ -5603,17 +5590,17 @@ "phpstan/phpstan": "^1.10.0", "psr/cache": "^1.0|^2.0|^3.0", "psr/log": "^1.0", - "symfony/asset": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/browser-kit": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/cache": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/console": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/dependency-injection": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/form": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/messenger": "^4.4|^5.3|^6.0|^7.0", - "symfony/phpunit-bridge": "^7.0.2", - "symfony/templating": "^3.4|^4.4|^5.3|^6.0", - "symfony/validator": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/yaml": "^3.4|^4.4|^5.3|^6.0|^7.0" + "symfony/asset": "^5.4|^6.4|^7.3|^8.0", + "symfony/browser-kit": "^5.4|^6.4|^7.3|^8.0", + "symfony/cache": "^5.4|^6.4|^7.3|^8.0", + "symfony/console": "^5.4|^6.4|^7.3|^8.0", + "symfony/form": "^5.4|^6.4|^7.3|^8.0", + "symfony/messenger": "^5.4|^6.4|^7.3|^8.0", + "symfony/phpunit-bridge": "^7.3", + "symfony/runtime": "^5.4|^6.4|^7.3|^8.0", + "symfony/templating": "^5.4|^6.4|^7.3|^8.0", + "symfony/validator": "^5.4|^6.4|^7.3|^8.0", + "symfony/yaml": "^5.4|^6.4|^7.3|^8.0" }, "suggest": { "alcaeus/mongo-php-adapter": "required for mongodb components", @@ -5668,9 +5655,9 @@ ], "support": { "issues": "https://github.com/liip/LiipImagineBundle/issues", - "source": "https://github.com/liip/LiipImagineBundle/tree/2.15.0" + "source": "https://github.com/liip/LiipImagineBundle/tree/2.17.1" }, - "time": "2025-10-09T06:49:28+00:00" + "time": "2026-01-06T09:34:48+00:00" }, { "name": "lufiipe/insee-sierene", @@ -6583,16 +6570,16 @@ }, { "name": "nesbot/carbon", - "version": "3.11.0", + "version": "3.11.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "bdb375400dcd162624531666db4799b36b64e4a1" + "reference": "f438fcc98f92babee98381d399c65336f3a3827f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1", - "reference": "bdb375400dcd162624531666db4799b36b64e4a1", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", + "reference": "f438fcc98f92babee98381d399c65336f3a3827f", "shasum": "" }, "require": { @@ -6616,7 +6603,7 @@ "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.1.22", "phpunit/phpunit": "^10.5.53", - "squizlabs/php_codesniffer": "^3.13.4" + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" }, "bin": [ "bin/carbon" @@ -6659,14 +6646,14 @@ } ], "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "https://carbon.nesbot.com", + "homepage": "https://carbonphp.github.io/carbon/", "keywords": [ "date", "datetime", "time" ], "support": { - "docs": "https://carbon.nesbot.com/docs", + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", "issues": "https://github.com/CarbonPHP/carbon/issues", "source": "https://github.com/CarbonPHP/carbon" }, @@ -6684,7 +6671,7 @@ "type": "tidelift" } ], - "time": "2025-12-02T21:04:28+00:00" + "time": "2026-01-29T09:26:29+00:00" }, { "name": "overtrue/pinyin", @@ -7357,16 +7344,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.48", + "version": "3.0.49", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "64065a5679c50acb886e82c07aa139b0f757bb89" + "reference": "6233a1e12584754e6b5daa69fe1289b47775c1b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/64065a5679c50acb886e82c07aa139b0f757bb89", - "reference": "64065a5679c50acb886e82c07aa139b0f757bb89", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/6233a1e12584754e6b5daa69fe1289b47775c1b9", + "reference": "6233a1e12584754e6b5daa69fe1289b47775c1b9", "shasum": "" }, "require": { @@ -7447,7 +7434,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.48" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.49" }, "funding": [ { @@ -7463,7 +7450,7 @@ "type": "tidelift" } ], - "time": "2025-12-15T11:51:42+00:00" + "time": "2026-01-27T09:17:28+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -7514,33 +7501,33 @@ }, { "name": "presta/sitemap-bundle", - "version": "v4.2.0", + "version": "v4.3.0", "source": { "type": "git", "url": "https://github.com/prestaconcept/PrestaSitemapBundle.git", - "reference": "61eb5f2b5810a4f2f52bbc6a63186750c7d1f528" + "reference": "2fc8845e5cc0dfa2911615eb3aec1d4a1bd95eff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/prestaconcept/PrestaSitemapBundle/zipball/61eb5f2b5810a4f2f52bbc6a63186750c7d1f528", - "reference": "61eb5f2b5810a4f2f52bbc6a63186750c7d1f528", + "url": "https://api.github.com/repos/prestaconcept/PrestaSitemapBundle/zipball/2fc8845e5cc0dfa2911615eb3aec1d4a1bd95eff", + "reference": "2fc8845e5cc0dfa2911615eb3aec1d4a1bd95eff", "shasum": "" }, "require": { "ext-simplexml": "*", "php": ">=8.0", - "symfony/console": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0" }, "require-dev": { "doctrine/annotations": "^1.0", - "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^7.5|^8.0", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^10.0", "squizlabs/php_codesniffer": "^3.5", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/phpunit-bridge": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/phpunit-bridge": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "extra": { @@ -7576,9 +7563,9 @@ ], "support": { "issues": "https://github.com/prestaconcept/PrestaSitemapBundle/issues", - "source": "https://github.com/prestaconcept/PrestaSitemapBundle/tree/v4.2.0" + "source": "https://github.com/prestaconcept/PrestaSitemapBundle/tree/v4.3.0" }, - "time": "2025-07-31T12:29:35+00:00" + "time": "2025-12-16T16:40:00+00:00" }, { "name": "psr/cache", @@ -8361,20 +8348,20 @@ }, { "name": "scheb/2fa-backup-code", - "version": "v7.13.1", + "version": "v8.3.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-backup-code.git", - "reference": "35f1ace4be7be2c10158d2bb8284208499111db8" + "reference": "cf4251fcc24f4a39d1307d8bbfabecfbd21ed57b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/35f1ace4be7be2c10158d2bb8284208499111db8", - "reference": "35f1ace4be7be2c10158d2bb8284208499111db8", + "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/cf4251fcc24f4a39d1307d8bbfabecfbd21ed57b", + "reference": "cf4251fcc24f4a39d1307d8bbfabecfbd21ed57b", "shasum": "" }, "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "php": "~8.4.0 || ~8.5.0", "scheb/2fa-bundle": "self.version" }, "type": "library", @@ -8404,37 +8391,37 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-backup-code/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-backup-code/tree/v8.3.0" }, - "time": "2025-11-20T13:35:24+00:00" + "time": "2026-01-24T13:26:10+00:00" }, { "name": "scheb/2fa-bundle", - "version": "v7.13.1", + "version": "v8.3.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-bundle.git", - "reference": "edcc14456b508aab37ec792cfc36793d04226784" + "reference": "5d3349ed7fbaf9225896caf280ed4e69c9d69add" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/edcc14456b508aab37ec792cfc36793d04226784", - "reference": "edcc14456b508aab37ec792cfc36793d04226784", + "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/5d3349ed7fbaf9225896caf280ed4e69c9d69add", + "reference": "5d3349ed7fbaf9225896caf280ed4e69c9d69add", "shasum": "" }, "require": { "ext-json": "*", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", - "symfony/config": "^6.4 || ^7.0", - "symfony/dependency-injection": "^6.4 || ^7.0", - "symfony/event-dispatcher": "^6.4 || ^7.0", - "symfony/framework-bundle": "^6.4 || ^7.0", - "symfony/http-foundation": "^6.4 || ^7.0", - "symfony/http-kernel": "^6.4 || ^7.0", - "symfony/property-access": "^6.4 || ^7.0", - "symfony/security-bundle": "^6.4 || ^7.0", + "php": "~8.4.0 || ~8.5.0", + "symfony/config": "^7.4 || ^8.0", + "symfony/dependency-injection": "^7.4 || ^8.0", + "symfony/event-dispatcher": "^7.4 || ^8.0", + "symfony/framework-bundle": "^7.4 || ^8.0", + "symfony/http-foundation": "^7.4 || ^8.0", + "symfony/http-kernel": "^7.4 || ^8.0", + "symfony/property-access": "^7.4 || ^8.0", + "symfony/security-bundle": "^7.4 || ^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/twig-bundle": "^6.4 || ^7.0" + "symfony/twig-bundle": "^7.4 || ^8.0" }, "conflict": { "scheb/two-factor-bundle": "*" @@ -8472,26 +8459,26 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-bundle/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-bundle/tree/v8.3.0" }, - "time": "2025-12-18T15:29:07+00:00" + "time": "2026-01-24T13:26:10+00:00" }, { "name": "scheb/2fa-email", - "version": "v7.13.1", + "version": "v8.3.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-email.git", - "reference": "ee70a062dde6aa9d566f99d2b1ae40b544ddbcef" + "reference": "6deee3e397c3c189738fd063011f1a512667eb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-email/zipball/ee70a062dde6aa9d566f99d2b1ae40b544ddbcef", - "reference": "ee70a062dde6aa9d566f99d2b1ae40b544ddbcef", + "url": "https://api.github.com/repos/scheb/2fa-email/zipball/6deee3e397c3c189738fd063011f1a512667eb13", + "reference": "6deee3e397c3c189738fd063011f1a512667eb13", "shasum": "" }, "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "php": "~8.4.0 || ~8.5.0", "scheb/2fa-bundle": "self.version" }, "suggest": { @@ -8524,28 +8511,28 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-email/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-email/tree/v8.3.0" }, - "time": "2025-11-20T13:35:24+00:00" + "time": "2026-01-24T13:26:10+00:00" }, { "name": "scheb/2fa-google-authenticator", - "version": "v7.13.1", + "version": "v8.3.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-google-authenticator.git", - "reference": "7ad34bbde343a0770571464127ee072aacb70a58" + "reference": "b7b173fa2cb437cb16d5a42af487e7e73a5f3ba1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-google-authenticator/zipball/7ad34bbde343a0770571464127ee072aacb70a58", - "reference": "7ad34bbde343a0770571464127ee072aacb70a58", + "url": "https://api.github.com/repos/scheb/2fa-google-authenticator/zipball/b7b173fa2cb437cb16d5a42af487e7e73a5f3ba1", + "reference": "b7b173fa2cb437cb16d5a42af487e7e73a5f3ba1", "shasum": "" }, "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "php": "~8.4.0 || ~8.5.0", "scheb/2fa-bundle": "self.version", - "spomky-labs/otphp": "^11.0" + "spomky-labs/otphp": "^11.4" }, "suggest": { "symfony/validator": "Needed if you want to use the Google Authenticator TOTP validator constraint" @@ -8577,9 +8564,9 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-google-authenticator/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-google-authenticator/tree/v8.3.0" }, - "time": "2025-12-04T15:55:14+00:00" + "time": "2026-01-24T13:27:55+00:00" }, { "name": "sentry/sentry", @@ -8843,67 +8830,6 @@ ], "time": "2025-08-05T09:57:14+00:00" }, - { - "name": "spatie/mjml-php", - "version": "1.2.5", - "source": { - "type": "git", - "url": "https://github.com/spatie/mjml-php.git", - "reference": "0af0b3944617889df7bed69faca3819a0399feff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/mjml-php/zipball/0af0b3944617889df7bed69faca3819a0399feff", - "reference": "0af0b3944617889df7bed69faca3819a0399feff", - "shasum": "" - }, - "require": { - "php": "^8.1", - "symfony/process": "^6.3.2|^7.0" - }, - "require-dev": { - "laravel/pint": "^1.11", - "pestphp/pest": "^2.16", - "spatie/ray": "^1.37.2" - }, - "suggest": { - "spatie/mjml-sidecar": "When you want to run MJML compilation through Sidecar in a Laravel project" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Mjml\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "role": "Developer" - } - ], - "description": "Convert MJML to HTML using PHP", - "homepage": "https://github.com/spatie/mjml-php", - "keywords": [ - "mjml-php", - "spatie" - ], - "support": { - "issues": "https://github.com/spatie/mjml-php/issues", - "source": "https://github.com/spatie/mjml-php/tree/1.2.5" - }, - "funding": [ - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2025-03-17T19:50:19+00:00" - }, { "name": "spomky-labs/base64url", "version": "v2.0.4", @@ -9221,46 +9147,54 @@ }, { "name": "spomky-labs/pwa-bundle", - "version": "1.3.5", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/pwa-bundle.git", - "reference": "3530dc2c02544e7f7518d4dfab28b1615630ae27" + "reference": "661718cf2c888fd9a04cef36a4fe719e4fcf3250" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/pwa-bundle/zipball/3530dc2c02544e7f7518d4dfab28b1615630ae27", - "reference": "3530dc2c02544e7f7518d4dfab28b1615630ae27", + "url": "https://api.github.com/repos/Spomky-Labs/pwa-bundle/zipball/661718cf2c888fd9a04cef36a4fe719e4fcf3250", + "reference": "661718cf2c888fd9a04cef36a4fe719e4fcf3250", "shasum": "" }, "require": { "php": ">=8.2", - "phpdocumentor/reflection-docblock": "^5.3", + "phpdocumentor/reflection-docblock": "^5.3|^6.0", "psr/log": "^1.1|^2.0|^3.0", - "symfony/asset": "^6.4|^7.0", - "symfony/asset-mapper": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/asset-mapper": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^3.5", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^3.0", + "symfony/web-link": "^6.4|^7.0|^8.0", "twig/twig": "^3.8" }, "require-dev": { + "dbrekelmans/bdi": "*", "matthiasnoback/symfony-config-test": "^5.1|^6.0", - "nelmio/security-bundle": "^3.0", - "symfony/console": "^7.2", - "symfony/filesystem": "^7.1", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/monolog-bundle": "^3.10", - "symfony/translation": "^7.0", + "monolog/monolog": "^3.0", + "nelmio/security-bundle": "^3.3", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/monolog-bridge": "^6.4|^7.0|^8.0", + "symfony/monolog-bundle": "^3.10|^4.0", + "symfony/panther": "^2.3", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^7.0|^8.0", "symfony/ux-icons": "^2.29", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "suggest": { "ext-gd": "Required to generate icons (or Imagick).", @@ -9305,7 +9239,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/pwa-bundle/issues", - "source": "https://github.com/Spomky-Labs/pwa-bundle/tree/1.3.5" + "source": "https://github.com/Spomky-Labs/pwa-bundle/tree/1.5.0" }, "funding": [ { @@ -9321,7 +9255,7 @@ "type": "patreon" } ], - "time": "2025-10-26T00:12:45+00:00" + "time": "2026-01-28T23:16:07+00:00" }, { "name": "spomky-labs/web-push-bundle", @@ -9587,16 +9521,16 @@ }, { "name": "stripe/stripe-php", - "version": "v19.2.0", + "version": "v19.3.0", "source": { "type": "git", "url": "https://github.com/stripe/stripe-php.git", - "reference": "e444fbc524cd3d6583dde2c5b375d26174c54d96" + "reference": "462272ae7560ee29bb891763fd0967d5a77784e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stripe/stripe-php/zipball/e444fbc524cd3d6583dde2c5b375d26174c54d96", - "reference": "e444fbc524cd3d6583dde2c5b375d26174c54d96", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/462272ae7560ee29bb891763fd0967d5a77784e5", + "reference": "462272ae7560ee29bb891763fd0967d5a77784e5", "shasum": "" }, "require": { @@ -9640,31 +9574,31 @@ ], "support": { "issues": "https://github.com/stripe/stripe-php/issues", - "source": "https://github.com/stripe/stripe-php/tree/v19.2.0" + "source": "https://github.com/stripe/stripe-php/tree/v19.3.0" }, - "time": "2026-01-16T21:28:14+00:00" + "time": "2026-01-28T21:15:45+00:00" }, { "name": "symfony/amazon-mailer", - "version": "v7.3.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/amazon-mailer.git", - "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c" + "reference": "1636d14445bcff2c63c300cf34e046ce87843452" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/7266d4285147c890f4f7f42dc875fe5a6df8006c", - "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/1636d14445bcff2c63c300cf34e046ce87843452", + "reference": "1636d14445bcff2c63c300cf34e046ce87843452", "shasum": "" }, "require": { "async-aws/ses": "^1.8", - "php": ">=8.2", - "symfony/mailer": "^7.2" + "php": ">=8.4", + "symfony/mailer": "^7.4|^8.0" }, "require-dev": { - "symfony/http-client": "^6.4|^7.0" + "symfony/http-client": "^7.4|^8.0" }, "type": "symfony-mailer-bridge", "autoload": { @@ -9692,7 +9626,7 @@ "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/amazon-mailer/tree/v7.3.0" + "source": "https://github.com/symfony/amazon-mailer/tree/v8.0.0" }, "funding": [ { @@ -9703,37 +9637,38 @@ "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-02-26T16:10:57+00:00" + "time": "2025-08-04T07:36:47+00:00" }, { "name": "symfony/asset", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "da95c6aba17f7e831744c2a09fd360e32a3d0f84" + "reference": "2401c7e9f223969f0979eeb884a09fa6f8d7e49b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/da95c6aba17f7e831744c2a09fd360e32a3d0f84", - "reference": "da95c6aba17f7e831744c2a09fd360e32a3d0f84", + "url": "https://api.github.com/repos/symfony/asset/zipball/2401c7e9f223969f0979eeb884a09fa6f8d7e49b", + "reference": "2401c7e9f223969f0979eeb884a09fa6f8d7e49b", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/http-foundation": "<6.4" + "php": ">=8.4" }, "require-dev": { - "symfony/http-client": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0" + "symfony/http-client": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -9761,7 +9696,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v7.3.10" + "source": "https://github.com/symfony/asset/tree/v8.0.4" }, "funding": [ { @@ -9781,43 +9716,40 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:28:39+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/asset-mapper", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/asset-mapper.git", - "reference": "8325b9e34ad1b03c9a8a8414f215ea24949e1207" + "reference": "14184221c21c2622e62f2c009a6cc25c5570e4ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/8325b9e34ad1b03c9a8a8414f215ea24949e1207", - "reference": "8325b9e34ad1b03c9a8a8414f215ea24949e1207", + "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/14184221c21c2622e62f2c009a6cc25c5570e4ba", + "reference": "14184221c21c2622e62f2c009a6cc25c5570e4ba", "shasum": "" }, "require": { "composer/semver": "^3.0", - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^7.1", - "symfony/http-client": "^6.4|^7.0" - }, - "conflict": { - "symfony/framework-bundle": "<6.4" + "php": ">=8.4", + "symfony/filesystem": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0" }, "require-dev": { - "symfony/asset": "^6.4|^7.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", + "symfony/asset": "^7.4|^8.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", "symfony/event-dispatcher-contracts": "^3.0", - "symfony/finder": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/web-link": "^6.4|^7.0" + "symfony/finder": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/web-link": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -9845,7 +9777,7 @@ "description": "Maps directories of assets & makes them available in a public directory with versioned filenames.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset-mapper/tree/v7.3.10" + "source": "https://github.com/symfony/asset-mapper/tree/v8.0.4" }, "funding": [ { @@ -9865,36 +9797,34 @@ "type": "tidelift" } ], - "time": "2026-01-13T08:38:55+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/cache", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "129b3a6337511b28bde97a10f98fc4372da3e113" + "reference": "92e9960386c7e01f58198038c199d522959a843c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/129b3a6337511b28bde97a10f98fc4372da3e113", - "reference": "129b3a6337511b28bde97a10f98fc4372da3e113", + "url": "https://api.github.com/repos/symfony/cache/zipball/92e9960386c7e01f58198038c199d522959a843c", + "reference": "92e9960386c7e01f58198038c199d522959a843c", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^3.6", - "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^7.4|^8.0" }, "conflict": { - "doctrine/dbal": "<3.6", - "symfony/dependency-injection": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/var-dumper": "<6.4" + "doctrine/dbal": "<4.3", + "ext-redis": "<6.1", + "ext-relay": "<0.12.1" }, "provide": { "psr/cache-implementation": "2.0|3.0", @@ -9903,16 +9833,16 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", + "doctrine/dbal": "^4.3", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/filesystem": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/filesystem": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -9947,7 +9877,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.3.10" + "source": "https://github.com/symfony/cache/tree/v8.0.5" }, "funding": [ { @@ -9967,7 +9897,7 @@ "type": "tidelift" } ], - "time": "2026-01-23T12:58:13+00:00" + "time": "2026-01-27T16:18:07+00:00" }, { "name": "symfony/cache-contracts", @@ -10047,22 +9977,21 @@ }, { "name": "symfony/clock", - "version": "v7.3.8", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "bf3ab8ea07408cb91aef86e3b2761d2d0f011e7c" + "reference": "832119f9b8dbc6c8e6f65f30c5969eca1e88764f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/bf3ab8ea07408cb91aef86e3b2761d2d0f011e7c", - "reference": "bf3ab8ea07408cb91aef86e3b2761d2d0f011e7c", + "url": "https://api.github.com/repos/symfony/clock/zipball/832119f9b8dbc6c8e6f65f30c5969eca1e88764f", + "reference": "832119f9b8dbc6c8e6f65f30c5969eca1e88764f", "shasum": "" }, "require": { - "php": ">=8.2", - "psr/clock": "^1.0", - "symfony/polyfill-php83": "^1.28" + "php": ">=8.4", + "psr/clock": "^1.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -10101,7 +10030,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.3.8" + "source": "https://github.com/symfony/clock/tree/v8.0.0" }, "funding": [ { @@ -10121,38 +10050,37 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:21:00+00:00" + "time": "2025-11-12T15:46:48+00:00" }, { "name": "symfony/config", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "26ddb5ea228c55986ac9dd5273bd6b4e3d07eb61" + "reference": "8f45af92f08f82902827a8b6f403aaf49d893539" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/26ddb5ea228c55986ac9dd5273bd6b4e3d07eb61", - "reference": "26ddb5ea228c55986ac9dd5273bd6b4e3d07eb61", + "url": "https://api.github.com/repos/symfony/config/zipball/8f45af92f08f82902827a8b6f403aaf49d893539", + "reference": "8f45af92f08f82902827a8b6f403aaf49d893539", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1", - "symfony/polyfill-ctype": "~1.8" + "symfony/filesystem": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/finder": "<6.4", "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -10180,7 +10108,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.3.10" + "source": "https://github.com/symfony/config/tree/v8.0.4" }, "funding": [ { @@ -10200,51 +10128,43 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:52:41+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/console", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a28c3e5b4df406e8fae8e9b18c40557b5dfc430c" + "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a28c3e5b4df406e8fae8e9b18c40557b5dfc430c", - "reference": "a28c3e5b4df406e8fae8e9b18c40557b5dfc430c", + "url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b", + "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" - }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/dotenv": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/lock": "<6.4", - "symfony/process": "<6.4" + "symfony/string": "^7.4|^8.0" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -10278,7 +10198,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.10" + "source": "https://github.com/symfony/console/tree/v8.0.4" }, "funding": [ { @@ -10298,43 +10218,40 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:52:14+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "46aadd0ecb1aed639481353c61aa155231a29ba9" + "reference": "40a6c455ade7e3bf25900d6b746d40cfa2573e26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/46aadd0ecb1aed639481353c61aa155231a29ba9", - "reference": "46aadd0ecb1aed639481353c61aa155231a29ba9", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/40a6c455ade7e3bf25900d6b746d40cfa2573e26", + "reference": "40a6c455ade7e3bf25900d6b746d40cfa2573e26", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^3.5", - "symfony/var-exporter": "^6.4.20|^7.2.5" + "symfony/service-contracts": "^3.6", + "symfony/var-exporter": "^7.4|^8.0" }, "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<6.4", - "symfony/finder": "<6.4", - "symfony/yaml": "<6.4" + "ext-psr": "<1.1|>=2" }, "provide": { "psr/container-implementation": "1.1|2.0", "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -10362,7 +10279,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.3.10" + "source": "https://github.com/symfony/dependency-injection/tree/v8.0.5" }, "funding": [ { @@ -10382,7 +10299,7 @@ "type": "tidelift" } ], - "time": "2026-01-23T12:58:13+00:00" + "time": "2026-01-27T16:18:07+00:00" }, { "name": "symfony/deprecation-contracts", @@ -10453,68 +10370,57 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "98814d5e95e382150629619fa883e775baf6f340" + "reference": "0d07589d03ed7db1833bfe943635872a2e8aebb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/98814d5e95e382150629619fa883e775baf6f340", - "reference": "98814d5e95e382150629619fa883e775baf6f340", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/0d07589d03ed7db1833bfe943635872a2e8aebb2", + "reference": "0d07589d03ed7db1833bfe943635872a2e8aebb2", "shasum": "" }, "require": { "doctrine/event-manager": "^2", "doctrine/persistence": "^3.1|^4", - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0", + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { "doctrine/collections": "<1.8", - "doctrine/dbal": "<3.6", + "doctrine/dbal": "<4.3", "doctrine/lexer": "<1.1", - "doctrine/orm": "<2.15", - "symfony/cache": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/form": "<6.4.6|>=7,<7.0.6", - "symfony/http-foundation": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/lock": "<6.4", - "symfony/messenger": "<6.4", - "symfony/property-info": "<6.4", - "symfony/security-bundle": "<6.4", - "symfony/security-core": "<6.4", - "symfony/validator": "<6.4" + "doctrine/orm": "<3.4", + "symfony/property-info": "<8.0" }, "require-dev": { "doctrine/collections": "^1.8|^2.0", "doctrine/data-fixtures": "^1.1|^2", - "doctrine/dbal": "^3.6|^4", - "doctrine/orm": "^2.15|^3", + "doctrine/dbal": "^4.3", + "doctrine/orm": "^3.4", "psr/log": "^1|^2|^3", - "symfony/cache": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/doctrine-messenger": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/form": "^6.4.6|^7.0.6", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/security-core": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/type-info": "^7.1.8", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/doctrine-messenger": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/type-info": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -10542,7 +10448,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.3.10" + "source": "https://github.com/symfony/doctrine-bridge/tree/v8.0.4" }, "funding": [ { @@ -10562,26 +10468,26 @@ "type": "tidelift" } ], - "time": "2026-01-20T16:37:04+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/doctrine-messenger", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-messenger.git", - "reference": "1f92127e21794ebcdf70fac789f4d3ea78348527" + "reference": "81d0b288e90d462896d1dffcff99571dd9d1618c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/1f92127e21794ebcdf70fac789f4d3ea78348527", - "reference": "1f92127e21794ebcdf70fac789f4d3ea78348527", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/81d0b288e90d462896d1dffcff99571dd9d1618c", + "reference": "81d0b288e90d462896d1dffcff99571dd9d1618c", "shasum": "" }, "require": { - "doctrine/dbal": "^3.6|^4", - "php": ">=8.2", - "symfony/messenger": "^7.2", + "doctrine/dbal": "^4.3", + "php": ">=8.4", + "symfony/messenger": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -10589,8 +10495,8 @@ }, "require-dev": { "doctrine/persistence": "^1.3|^2|^3", - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0" + "symfony/property-access": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0" }, "type": "symfony-messenger-bridge", "autoload": { @@ -10618,7 +10524,7 @@ "description": "Symfony Doctrine Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-messenger/tree/v7.3.10" + "source": "https://github.com/symfony/doctrine-messenger/tree/v8.0.5" }, "funding": [ { @@ -10638,32 +10544,28 @@ "type": "tidelift" } ], - "time": "2026-01-08T08:24:00+00:00" + "time": "2026-01-27T16:18:07+00:00" }, { "name": "symfony/dotenv", - "version": "v7.3.8", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "8c53fef39685ce76f208b4ccdc1e224f7e626c3f" + "reference": "460b4067a85288c59a59ce8c1bfb3942e71fd85c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/8c53fef39685ce76f208b4ccdc1e224f7e626c3f", - "reference": "8c53fef39685ce76f208b4ccdc1e224f7e626c3f", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/460b4067a85288c59a59ce8c1bfb3942e71fd85c", + "reference": "460b4067a85288c59a59ce8c1bfb3942e71fd85c", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/console": "<6.4", - "symfony/process": "<6.4" + "php": ">=8.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -10696,7 +10598,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v7.3.8" + "source": "https://github.com/symfony/dotenv/tree/v8.0.0" }, "funding": [ { @@ -10716,36 +10618,36 @@ "type": "tidelift" } ], - "time": "2025-11-16T10:09:06+00:00" + "time": "2025-11-16T10:17:21+00:00" }, { "name": "symfony/error-handler", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "c2ee39c0f4840971da6d4b8a1fd910ed470e2c93" + "reference": "7620b97ec0ab1d2d6c7fb737aa55da411bea776a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/c2ee39c0f4840971da6d4b8a1fd910ed470e2c93", - "reference": "c2ee39c0f4840971da6d4b8a1fd910ed470e2c93", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/7620b97ec0ab1d2d6c7fb737aa55da411bea776a", + "reference": "7620b97ec0ab1d2d6c7fb737aa55da411bea776a", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^7.4|^8.0" }, "conflict": { - "symfony/deprecation-contracts": "<2.5", - "symfony/http-kernel": "<6.4" + "symfony/deprecation-contracts": "<2.5" }, "require-dev": { - "symfony/console": "^6.4|^7.0", + "symfony/console": "^7.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ @@ -10777,7 +10679,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.10" + "source": "https://github.com/symfony/error-handler/tree/v8.0.4" }, "funding": [ { @@ -10797,28 +10699,28 @@ "type": "tidelift" } ], - "time": "2026-01-20T16:37:04+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "2abf563596d8af09bbbfe4c6079bdffd7ed3f9f8" + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2abf563596d8af09bbbfe4c6079bdffd7ed3f9f8", - "reference": "2abf563596d8af09bbbfe4c6079bdffd7ed3f9f8", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<6.4", + "symfony/security-http": "<7.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -10827,13 +10729,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -10861,7 +10764,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.10" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.4" }, "funding": [ { @@ -10881,7 +10784,7 @@ "type": "tidelift" } ], - "time": "2026-01-05T11:42:02+00:00" + "time": "2026-01-05T11:45:55+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -10961,22 +10864,21 @@ }, { "name": "symfony/expression-language", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "bb4594cdd692b4f582b9f8a3aa15cde4f749fea7" + "reference": "83989cfbcf2ba08a400be339a88468b05ddc21c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/bb4594cdd692b4f582b9f8a3aa15cde4f749fea7", - "reference": "bb4594cdd692b4f582b9f8a3aa15cde4f749fea7", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/83989cfbcf2ba08a400be339a88468b05ddc21c9", + "reference": "83989cfbcf2ba08a400be339a88468b05ddc21c9", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/cache": "^6.4|^7.0", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.4", + "symfony/cache": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -11005,7 +10907,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v7.3.10" + "source": "https://github.com/symfony/expression-language/tree/v8.0.4" }, "funding": [ { @@ -11025,29 +10927,29 @@ "type": "tidelift" } ], - "time": "2026-01-05T08:45:46+00:00" + "time": "2026-01-05T09:27:50+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.8", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ce0b94a0e57b7499520d9e5150da9716d729a645" + "reference": "d937d400b980523dc9ee946bb69972b5e619058d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ce0b94a0e57b7499520d9e5150da9716d729a645", - "reference": "ce0b94a0e57b7499520d9e5150da9716d729a645", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d", + "reference": "d937d400b980523dc9ee946bb69972b5e619058d", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "symfony/process": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -11075,7 +10977,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.8" + "source": "https://github.com/symfony/filesystem/tree/v8.0.1" }, "funding": [ { @@ -11095,27 +10997,27 @@ "type": "tidelift" } ], - "time": "2025-11-26T15:55:45+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/finder", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "283982e4af5569e58e4b9427f5187729fd05e513" + "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/283982e4af5569e58e4b9427f5187729fd05e513", - "reference": "283982e4af5569e58e4b9427f5187729fd05e513", + "url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0", + "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -11143,7 +11045,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.10" + "source": "https://github.com/symfony/finder/tree/v8.0.5" }, "funding": [ { @@ -11163,7 +11065,7 @@ "type": "tidelift" } ], - "time": "2026-01-12T12:03:18+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/flex", @@ -11240,56 +11142,50 @@ }, { "name": "symfony/form", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "4bc84400e208bd82e3a68f88f4fe26b8d4d85181" + "reference": "c34ec2c2648e2dfedab3ce7e3c6c86f8d89c3092" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/4bc84400e208bd82e3a68f88f4fe26b8d4d85181", - "reference": "4bc84400e208bd82e3a68f88f4fe26b8d4d85181", + "url": "https://api.github.com/repos/symfony/form/zipball/c34ec2c2648e2dfedab3ce7e3c6c86f8d89c3092", + "reference": "c34ec2c2648e2dfedab3ce7e3c6c86f8d89c3092", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/options-resolver": "^7.3", - "symfony/polyfill-ctype": "~1.8", + "php": ">=8.4", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/options-resolver": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-intl-icu": "^1.21", - "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^6.4|^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/property-access": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<6.4", - "symfony/error-handler": "<6.4", - "symfony/framework-bundle": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/intl": "<7.4", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<6.4" + "symfony/validator": "<7.4" }, "require-dev": { "doctrine/collections": "^1.0|^2.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/html-sanitizer": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/security-core": "^6.4|^7.0", - "symfony/security-csrf": "^6.4|^7.0", - "symfony/translation": "^6.4.3|^7.0.3", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/html-sanitizer": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -11317,7 +11213,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v7.3.10" + "source": "https://github.com/symfony/form/tree/v8.0.4" }, "funding": [ { @@ -11337,117 +11233,99 @@ "type": "tidelift" } ], - "time": "2026-01-23T10:44:29+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/framework-bundle", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "b6cfc86e770822b976dfffe32c1552f3fd3d2892" + "reference": "e2f9469e7a802dd7c0d193792afc494d68177c54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/b6cfc86e770822b976dfffe32c1552f3fd3d2892", - "reference": "b6cfc86e770822b976dfffe32c1552f3fd3d2892", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/e2f9469e7a802dd7c0d193792afc494d68177c54", + "reference": "e2f9469e7a802dd7c0d193792afc494d68177c54", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.2", - "symfony/cache": "^6.4|^7.0", - "symfony/config": "^7.3", - "symfony/dependency-injection": "^7.2", + "php": ">=8.4", + "symfony/cache": "^7.4|^8.0", + "symfony/config": "^7.4.4|^8.0.4", + "symfony/dependency-injection": "^7.4.4|^8.0.4", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^7.3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/filesystem": "^7.1", - "symfony/finder": "^6.4|^7.0", - "symfony/http-foundation": "^7.3", - "symfony/http-kernel": "^7.2", - "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^6.4|^7.0" + "symfony/error-handler": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/filesystem": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php85": "^1.32", + "symfony/routing": "^7.4|^8.0" }, "conflict": { "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/asset": "<6.4", - "symfony/asset-mapper": "<6.4", - "symfony/clock": "<6.4", - "symfony/console": "<6.4", - "symfony/dom-crawler": "<6.4", - "symfony/dotenv": "<6.4", - "symfony/form": "<6.4", - "symfony/http-client": "<6.4", - "symfony/json-streamer": ">=7.4", - "symfony/lock": "<6.4", - "symfony/mailer": "<6.4", - "symfony/messenger": "<6.4", - "symfony/mime": "<6.4", - "symfony/object-mapper": ">=7.4", - "symfony/property-access": "<6.4", - "symfony/property-info": "<6.4", - "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", - "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", - "symfony/security-core": "<6.4", - "symfony/security-csrf": "<7.2", - "symfony/serializer": "<7.2.5", - "symfony/stopwatch": "<6.4", - "symfony/translation": "<7.3", - "symfony/twig-bridge": "<6.4", - "symfony/twig-bundle": "<6.4", - "symfony/validator": "<6.4", - "symfony/web-profiler-bundle": "<6.4", - "symfony/webhook": "<7.2", - "symfony/workflow": "<7.3.0-beta2" + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/console": "<7.4", + "symfony/form": "<7.4", + "symfony/json-streamer": "<7.4", + "symfony/messenger": "<7.4", + "symfony/security-csrf": "<7.4", + "symfony/serializer": "<7.4", + "symfony/translation": "<7.4", + "symfony/webhook": "<7.4", + "symfony/workflow": "<7.4" }, "require-dev": { "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", - "symfony/asset": "^6.4|^7.0", - "symfony/asset-mapper": "^6.4|^7.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/dotenv": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/form": "^6.4|^7.0", - "symfony/html-sanitizer": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/json-streamer": "7.3.*", - "symfony/lock": "^6.4|^7.0", - "symfony/mailer": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/notifier": "^6.4|^7.0", - "symfony/object-mapper": "^v7.3.0-beta2", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/scheduler": "^6.4.4|^7.0.4", - "symfony/security-bundle": "^6.4|^7.0", - "symfony/semaphore": "^6.4|^7.0", - "symfony/serializer": "^7.2.5", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/string": "^6.4|^7.0", - "symfony/translation": "^7.3", - "symfony/twig-bundle": "^6.4|^7.0", - "symfony/type-info": "^7.1.8", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/web-link": "^6.4|^7.0", - "symfony/webhook": "^7.2", - "symfony/workflow": "^7.3", - "symfony/yaml": "^6.4|^7.0", - "twig/twig": "^3.12" + "symfony/asset": "^7.4|^8.0", + "symfony/asset-mapper": "^7.4|^8.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/dotenv": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/html-sanitizer": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/json-streamer": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/mailer": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/notifier": "^7.4|^8.0", + "symfony/object-mapper": "^7.4|^8.0", + "symfony/polyfill-intl-icu": "^1.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/scheduler": "^7.4|^8.0", + "symfony/security-bundle": "^7.4|^8.0", + "symfony/semaphore": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/string": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/twig-bundle": "^7.4|^8.0", + "symfony/type-info": "^7.4.1|^8.0.1", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/web-link": "^7.4|^8.0", + "symfony/webhook": "^7.4|^8.0", + "symfony/workflow": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -11475,7 +11353,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.3.10" + "source": "https://github.com/symfony/framework-bundle/tree/v8.0.5" }, "funding": [ { @@ -11495,35 +11373,31 @@ "type": "tidelift" } ], - "time": "2026-01-12T12:04:29+00:00" + "time": "2026-01-27T09:06:10+00:00" }, { "name": "symfony/http-client", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "6fa68bc7cd003ac2ad4c2a8780f5dfd8c8b0d23d" + "reference": "f9fdd372473e66469c6d32a4ed12efcffdea38c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/6fa68bc7cd003ac2ad4c2a8780f5dfd8c8b0d23d", - "reference": "6fa68bc7cd003ac2ad4c2a8780f5dfd8c8b0d23d", + "url": "https://api.github.com/repos/symfony/http-client/zipball/f9fdd372473e66469c6d32a4ed12efcffdea38c4", + "reference": "f9fdd372473e66469c6d32a4ed12efcffdea38c4", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "~3.4.4|^3.5.2", - "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "amphp/amp": "<2.5", - "amphp/socket": "<1.1", - "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.4" + "amphp/amp": "<3", + "php-http/discovery": "<1.15" }, "provide": { "php-http/async-client-implementation": "*", @@ -11532,19 +11406,19 @@ "symfony/http-client-implementation": "3.0" }, "require-dev": { - "amphp/http-client": "^4.2.1|^5.0", - "amphp/http-tunnel": "^1.0|^2.0", + "amphp/http-client": "^5.3.2", + "amphp/http-tunnel": "^2.0", "guzzlehttp/promises": "^1.4|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", - "symfony/amphp-http-client-meta": "^1.0|^2.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -11575,7 +11449,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.10" + "source": "https://github.com/symfony/http-client/tree/v8.0.5" }, "funding": [ { @@ -11595,7 +11469,7 @@ "type": "tidelift" } ], - "time": "2026-01-23T16:34:05+00:00" + "time": "2026-01-27T16:18:07+00:00" }, { "name": "symfony/http-client-contracts", @@ -11677,38 +11551,35 @@ }, { "name": "symfony/http-foundation", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "cc4ae963efd984204c0224605ae821382b791462" + "reference": "e3422806e6f6760dbed0ddbc0a7fbfb6b5ce96bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/cc4ae963efd984204c0224605ae821382b791462", - "reference": "cc4ae963efd984204c0224605ae821382b791462", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e3422806e6f6760dbed0ddbc0a7fbfb6b5ce96bb", + "reference": "e3422806e6f6760dbed0ddbc0a7fbfb6b5ce96bb", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { - "doctrine/dbal": "<3.6", - "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + "doctrine/dbal": "<4.3" }, "require-dev": { - "doctrine/dbal": "^3.6|^4", + "doctrine/dbal": "^4.3", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/clock": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -11736,7 +11607,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.10" + "source": "https://github.com/symfony/http-foundation/tree/v8.0.5" }, "funding": [ { @@ -11756,77 +11627,63 @@ "type": "tidelift" } ], - "time": "2026-01-09T11:56:19+00:00" + "time": "2026-01-27T16:18:07+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "c573fca3db08623a76066691b5c1e67cad857c71" + "reference": "20c1c5e41fc53928dbb670088f544f2d460d497d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c573fca3db08623a76066691b5c1e67cad857c71", - "reference": "c573fca3db08623a76066691b5c1e67cad857c71", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/20c1c5e41fc53928dbb670088f544f2d460d497d", + "reference": "20c1c5e41fc53928dbb670088f544f2d460d497d", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^7.3", - "symfony/http-foundation": "^7.3", + "symfony/error-handler": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/browser-kit": "<6.4", - "symfony/cache": "<6.4", - "symfony/config": "<6.4", - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<6.4", - "symfony/form": "<6.4", - "symfony/http-client": "<6.4", + "symfony/flex": "<2.10", "symfony/http-client-contracts": "<2.5", - "symfony/mailer": "<6.4", - "symfony/messenger": "<6.4", - "symfony/translation": "<6.4", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<6.4", - "symfony/validator": "<6.4", - "symfony/var-dumper": "<6.4", - "twig/twig": "<3.12" + "twig/twig": "<3.21" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^7.1", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^7.1", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0", - "twig/twig": "^3.12" + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0", + "twig/twig": "^3.21" }, "type": "library", "autoload": { @@ -11854,7 +11711,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.3.10" + "source": "https://github.com/symfony/http-kernel/tree/v8.0.5" }, "funding": [ { @@ -11874,32 +11731,31 @@ "type": "tidelift" } ], - "time": "2026-01-24T17:51:44+00:00" + "time": "2026-01-28T10:46:31+00:00" }, { "name": "symfony/intl", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "f5b5b91176221de5d394a15d4ecb236908a756fe" + "reference": "8d049269c2accca0b02e5f9de39f3ee92ebc4468" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/f5b5b91176221de5d394a15d4ecb236908a756fe", - "reference": "f5b5b91176221de5d394a15d4ecb236908a756fe", + "url": "https://api.github.com/repos/symfony/intl/zipball/8d049269c2accca0b02e5f9de39f3ee92ebc4468", + "reference": "8d049269c2accca0b02e5f9de39f3ee92ebc4468", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=8.4" }, "conflict": { - "symfony/string": "<7.1" + "symfony/string": "<7.4" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/filesystem": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -11944,7 +11800,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v7.3.10" + "source": "https://github.com/symfony/intl/tree/v8.0.4" }, "funding": [ { @@ -11964,43 +11820,39 @@ "type": "tidelift" } ], - "time": "2026-01-12T12:03:18+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "08a5b0114057fdfa3fd3e8fa3d7233a48e9363b9" + "reference": "a074d353f5b5a81d356652e8a2034fdd0501420b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/08a5b0114057fdfa3fd3e8fa3d7233a48e9363b9", - "reference": "08a5b0114057fdfa3fd3e8fa3d7233a48e9363b9", + "url": "https://api.github.com/repos/symfony/mailer/zipball/a074d353f5b5a81d356652e8a2034fdd0501420b", + "reference": "a074d353f5b5a81d356652e8a2034fdd0501420b", "shasum": "" }, "require": { "egulias/email-validator": "^2.1.10|^3|^4", - "php": ">=8.2", + "php": ">=8.4", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<6.4", - "symfony/messenger": "<6.4", - "symfony/mime": "<6.4", - "symfony/twig-bridge": "<6.4" + "symfony/http-client-contracts": "<2.5" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/twig-bridge": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -12028,7 +11880,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.10" + "source": "https://github.com/symfony/mailer/tree/v8.0.4" }, "funding": [ { @@ -12048,52 +11900,49 @@ "type": "tidelift" } ], - "time": "2026-01-07T22:18:08+00:00" + "time": "2026-01-08T08:40:07+00:00" }, { "name": "symfony/messenger", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "6e140779edbbea9d81d17a4b4f1862a89bf74561" + "reference": "3483db96bcc33310cd1807d2b962e7e01d9f41c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/6e140779edbbea9d81d17a4b4f1862a89bf74561", - "reference": "6e140779edbbea9d81d17a4b4f1862a89bf74561", + "url": "https://api.github.com/repos/symfony/messenger/zipball/3483db96bcc33310cd1807d2b962e7e01d9f41c2", + "reference": "3483db96bcc33310cd1807d2b962e7e01d9f41c2", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/log": "^1|^2|^3", - "symfony/clock": "^6.4|^7.0", - "symfony/deprecation-contracts": "^2.5|^3" + "symfony/clock": "^7.4|^8.0" }, "conflict": { - "symfony/console": "<7.2", - "symfony/event-dispatcher": "<6.4", + "symfony/console": "<7.4", "symfony/event-dispatcher-contracts": "<2.5", - "symfony/framework-bundle": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/lock": "<6.4", - "symfony/serializer": "<6.4" + "symfony/lock": "<7.4", + "symfony/serializer": "<7.4.4|>=8.0,<8.0.4" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/console": "^7.2", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/serializer": "^7.4.4|^8.0.4", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0" + "symfony/stopwatch": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -12121,7 +11970,7 @@ "description": "Helps applications send and receive messages to/from other applications or via message queues", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/messenger/tree/v7.3.10" + "source": "https://github.com/symfony/messenger/tree/v8.0.4" }, "funding": [ { @@ -12141,43 +11990,41 @@ "type": "tidelift" } ], - "time": "2026-01-07T22:25:05+00:00" + "time": "2026-01-08T22:36:47+00:00" }, { "name": "symfony/mime", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "df07e423bb8e45b3180a499a7ab1055ee161ce55" + "reference": "543d01b6ee4b8eb80ce9349186ad530eb8704252" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/df07e423bb8e45b3180a499a7ab1055ee161ce55", - "reference": "df07e423bb8e45b3180a499a7ab1055ee161ce55", + "url": "https://api.github.com/repos/symfony/mime/zipball/543d01b6ee4b8eb80ce9349186ad530eb8704252", + "reference": "543d01b6ee4b8eb80ce9349186ad530eb8704252", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<6.4", - "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "phpdocumentor/reflection-docblock": "^5.2", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -12209,7 +12056,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.10" + "source": "https://github.com/symfony/mime/tree/v8.0.5" }, "funding": [ { @@ -12229,41 +12076,36 @@ "type": "tidelift" } ], - "time": "2026-01-08T14:46:32+00:00" + "time": "2026-01-27T09:06:10+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "8e57eb82ea914604af3fae0df346123f6d1898c8" + "reference": "7c3da570ec252d5ca1212945ddbbf1dac4a0d779" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/8e57eb82ea914604af3fae0df346123f6d1898c8", - "reference": "8e57eb82ea914604af3fae0df346123f6d1898c8", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/7c3da570ec252d5ca1212945ddbbf1dac4a0d779", + "reference": "7c3da570ec252d5ca1212945ddbbf1dac4a0d779", "shasum": "" }, "require": { "monolog/monolog": "^3", - "php": ">=8.2", - "symfony/http-kernel": "^6.4|^7.0", + "php": ">=8.4", + "symfony/http-kernel": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, - "conflict": { - "symfony/console": "<6.4", - "symfony/http-foundation": "<6.4", - "symfony/security-core": "<6.4" - }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/mailer": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/security-core": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/mailer": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -12291,7 +12133,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v7.3.10" + "source": "https://github.com/symfony/monolog-bridge/tree/v8.0.4" }, "funding": [ { @@ -12311,37 +12153,36 @@ "type": "tidelift" } ], - "time": "2026-01-03T23:21:50+00:00" + "time": "2026-01-07T12:23:22+00:00" }, { "name": "symfony/monolog-bundle", - "version": "v3.11.1", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "0e675a6e08f791ef960dc9c7e392787111a3f0c1" + "reference": "3b4ee2717ee56c5e1edb516140a175eb2a72bc66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/0e675a6e08f791ef960dc9c7e392787111a3f0c1", - "reference": "0e675a6e08f791ef960dc9c7e392787111a3f0c1", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/3b4ee2717ee56c5e1edb516140a175eb2a72bc66", + "reference": "3b4ee2717ee56c5e1edb516140a175eb2a72bc66", "shasum": "" }, "require": { "composer-runtime-api": "^2.0", - "monolog/monolog": "^1.25.1 || ^2.0 || ^3.0", - "php": ">=8.1", - "symfony/config": "^6.4 || ^7.0", - "symfony/dependency-injection": "^6.4 || ^7.0", - "symfony/deprecation-contracts": "^2.5 || ^3.0", - "symfony/http-kernel": "^6.4 || ^7.0", - "symfony/monolog-bridge": "^6.4 || ^7.0", + "monolog/monolog": "^3.5", + "php": ">=8.2", + "symfony/config": "^7.3 || ^8.0", + "symfony/dependency-injection": "^7.3 || ^8.0", + "symfony/http-kernel": "^7.3 || ^8.0", + "symfony/monolog-bridge": "^7.3 || ^8.0", "symfony/polyfill-php84": "^1.30" }, "require-dev": { - "symfony/console": "^6.4 || ^7.0", - "symfony/phpunit-bridge": "^7.3.3", - "symfony/yaml": "^6.4 || ^7.0" + "phpunit/phpunit": "^11.5.41 || ^12.3", + "symfony/console": "^7.3 || ^8.0", + "symfony/yaml": "^7.3 || ^8.0" }, "type": "symfony-bundle", "autoload": { @@ -12371,7 +12212,7 @@ ], "support": { "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.11.1" + "source": "https://github.com/symfony/monolog-bundle/tree/v4.0.1" }, "funding": [ { @@ -12391,39 +12232,37 @@ "type": "tidelift" } ], - "time": "2025-12-08T07:58:26+00:00" + "time": "2025-12-08T08:00:13+00:00" }, { "name": "symfony/notifier", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/notifier.git", - "reference": "0944e40532b1743814000917250abd5f99b50597" + "reference": "dfd19f610f096d549429f9391d620bb16e67546e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/notifier/zipball/0944e40532b1743814000917250abd5f99b50597", - "reference": "0944e40532b1743814000917250abd5f99b50597", + "url": "https://api.github.com/repos/symfony/notifier/zipball/dfd19f610f096d549429f9391d620bb16e67546e", + "reference": "dfd19f610f096d549429f9391d620bb16e67546e", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/event-dispatcher": "<6.4", "symfony/event-dispatcher-contracts": "<2.5", - "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<6.4" + "symfony/http-client-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/http-client": "^6.4|^7.0", + "symfony/http-client": "^7.4|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0" + "symfony/http-foundation": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -12455,7 +12294,7 @@ "notifier" ], "support": { - "source": "https://github.com/symfony/notifier/tree/v7.3.10" + "source": "https://github.com/symfony/notifier/tree/v8.0.4" }, "funding": [ { @@ -12475,24 +12314,24 @@ "type": "tidelift" } ], - "time": "2026-01-05T08:45:46+00:00" + "time": "2026-01-08T22:36:47+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.3.8", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "772dfbe01306d03f759d492f6796dd8c9260bb5c" + "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/772dfbe01306d03f759d492f6796dd8c9260bb5c", - "reference": "772dfbe01306d03f759d492f6796dd8c9260bb5c", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7", + "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -12526,7 +12365,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.8" + "source": "https://github.com/symfony/options-resolver/tree/v8.0.0" }, "funding": [ { @@ -12546,31 +12385,28 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:21:00+00:00" + "time": "2025-11-12T15:55:31+00:00" }, { "name": "symfony/password-hasher", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "bfbe5a6490e9a911212c8060a22d22405684f6c5" + "reference": "ca6af4e20357d58d50c818d676cf2e2dd5e53b02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/bfbe5a6490e9a911212c8060a22d22405684f6c5", - "reference": "bfbe5a6490e9a911212c8060a22d22405684f6c5", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/ca6af4e20357d58d50c818d676cf2e2dd5e53b02", + "reference": "ca6af4e20357d58d50c818d676cf2e2dd5e53b02", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/security-core": "<6.4" + "php": ">=8.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/security-core": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -12602,7 +12438,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v7.3.10" + "source": "https://github.com/symfony/password-hasher/tree/v8.0.4" }, "funding": [ { @@ -12622,7 +12458,7 @@ "type": "tidelift" } ], - "time": "2026-01-01T22:03:12+00:00" + "time": "2026-01-01T23:07:29+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -13376,20 +13212,20 @@ }, { "name": "symfony/process", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "4424bc14e7dedec472440cc991f961f22343caaa" + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/4424bc14e7dedec472440cc991f961f22343caaa", - "reference": "4424bc14e7dedec472440cc991f961f22343caaa", + "url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "type": "library", "autoload": { @@ -13417,7 +13253,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.10" + "source": "https://github.com/symfony/process/tree/v8.0.5" }, "funding": [ { @@ -13437,28 +13273,29 @@ "type": "tidelift" } ], - "time": "2026-01-20T09:23:00+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/property-access", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "23cd9b9b8146bd5fcd190e7ecf46c84d18588110" + "reference": "a35a5ec85b605d0d1a9fd802cb44d87682c746fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/23cd9b9b8146bd5fcd190e7ecf46c84d18588110", - "reference": "23cd9b9b8146bd5fcd190e7ecf46c84d18588110", + "url": "https://api.github.com/repos/symfony/property-access/zipball/a35a5ec85b605d0d1a9fd802cb44d87682c746fd", + "reference": "a35a5ec85b605d0d1a9fd802cb44d87682c746fd", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4" + "php": ">=8.4", + "symfony/property-info": "^7.4.4|^8.0.4" }, "require-dev": { - "symfony/cache": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -13497,7 +13334,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.3.10" + "source": "https://github.com/symfony/property-access/tree/v8.0.4" }, "funding": [ { @@ -13517,41 +13354,37 @@ "type": "tidelift" } ], - "time": "2026-01-05T08:45:46+00:00" + "time": "2026-01-05T09:27:50+00:00" }, { "name": "symfony/property-info", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "2b6410e451dc9175694aadd4f93aad6efbc57d81" + "reference": "9d987224b54758240e80a062c5e414431bbf84de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/2b6410e451dc9175694aadd4f93aad6efbc57d81", - "reference": "2b6410e451dc9175694aadd4f93aad6efbc57d81", + "url": "https://api.github.com/repos/symfony/property-info/zipball/9d987224b54758240e80a062c5e414431bbf84de", + "reference": "9d987224b54758240e80a062c5e414431bbf84de", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0", - "symfony/type-info": "~7.3.10|^7.4.4" + "php": ">=8.4", + "symfony/string": "^7.4|^8.0", + "symfony/type-info": "^7.4.4|^8.0.4" }, "conflict": { - "phpdocumentor/reflection-docblock": "<5.2", - "phpdocumentor/type-resolver": "<1.5.1", - "symfony/cache": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/serializer": "<6.4" + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1" }, "require-dev": { "phpdocumentor/reflection-docblock": "^5.2", "phpstan/phpdoc-parser": "^1.0|^2.0", - "symfony/cache": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -13587,7 +13420,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v7.3.10" + "source": "https://github.com/symfony/property-info/tree/v8.0.5" }, "funding": [ { @@ -13607,40 +13440,40 @@ "type": "tidelift" } ], - "time": "2026-01-23T10:44:29+00:00" + "time": "2026-01-27T16:18:07+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "5bf565c44d5358cf20b1e2bd2dc736a7b43c07de" + "reference": "d6edf266746dd0b8e81e754a79da77b08dc00531" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/5bf565c44d5358cf20b1e2bd2dc736a7b43c07de", - "reference": "5bf565c44d5358cf20b1e2bd2dc736a7b43c07de", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/d6edf266746dd0b8e81e754a79da77b08dc00531", + "reference": "d6edf266746dd0b8e81e754a79da77b08dc00531", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/http-message": "^1.0|^2.0", - "symfony/http-foundation": "^6.4|^7.0" + "symfony/http-foundation": "^7.4|^8.0" }, "conflict": { - "php-http/discovery": "<1.15", - "symfony/http-kernel": "<6.4" + "php-http/discovery": "<1.15" }, "require-dev": { "nyholm/psr7": "^1.1", "php-http/discovery": "^1.15", "psr/log": "^1.1.4|^2|^3", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0" + "symfony/browser-kit": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -13674,7 +13507,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.3.10" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v8.0.4" }, "funding": [ { @@ -13694,30 +13527,35 @@ "type": "tidelift" } ], - "time": "2026-01-03T23:21:50+00:00" + "time": "2026-01-03T23:40:55+00:00" }, { "name": "symfony/redis-messenger", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/redis-messenger.git", - "reference": "e7057e3e9f1f2beb411e98b996483315cad35416" + "reference": "70db9083adc922f150f819311453afe8ad096ea9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/e7057e3e9f1f2beb411e98b996483315cad35416", - "reference": "e7057e3e9f1f2beb411e98b996483315cad35416", + "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/70db9083adc922f150f819311453afe8ad096ea9", + "reference": "70db9083adc922f150f819311453afe8ad096ea9", "shasum": "" }, "require": { "ext-redis": "*", - "php": ">=8.2", - "symfony/messenger": "^7.3" + "php": ">=8.4", + "symfony/messenger": "^7.4|^8.0" + }, + "conflict": { + "ext-redis": "<6.1", + "ext-relay": "<0.12" }, "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0" + "symfony/property-access": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "symfony-messenger-bridge", "autoload": { @@ -13745,7 +13583,7 @@ "description": "Symfony Redis extension Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/redis-messenger/tree/v7.3.10" + "source": "https://github.com/symfony/redis-messenger/tree/v8.0.4" }, "funding": [ { @@ -13765,38 +13603,33 @@ "type": "tidelift" } ], - "time": "2026-01-01T22:03:12+00:00" + "time": "2026-01-01T23:07:29+00:00" }, { "name": "symfony/routing", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "f66bf4fc34db04b15033d009b3b2f986f6970a67" + "reference": "4a2bc08d1c35307239329f434d45c2bfe8241fa9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/f66bf4fc34db04b15033d009b3b2f986f6970a67", - "reference": "f66bf4fc34db04b15033d009b3b2f986f6970a67", + "url": "https://api.github.com/repos/symfony/routing/zipball/4a2bc08d1c35307239329f434d45c2bfe8241fa9", + "reference": "4a2bc08d1c35307239329f434d45c2bfe8241fa9", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/deprecation-contracts": "^2.5|^3" }, - "conflict": { - "symfony/config": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/yaml": "<6.4" - }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -13830,7 +13663,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.10" + "source": "https://github.com/symfony/routing/tree/v8.0.4" }, "funding": [ { @@ -13850,35 +13683,35 @@ "type": "tidelift" } ], - "time": "2026-01-12T12:03:18+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symfony/runtime", - "version": "v7.3.8", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "9146981807ca9f0491dea6ccabe36a48e4b12cc0" + "reference": "73b34037b23db051048ba2873031ddb89be9f19d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/9146981807ca9f0491dea6ccabe36a48e4b12cc0", - "reference": "9146981807ca9f0491dea6ccabe36a48e4b12cc0", + "url": "https://api.github.com/repos/symfony/runtime/zipball/73b34037b23db051048ba2873031ddb89be9f19d", + "reference": "73b34037b23db051048ba2873031ddb89be9f19d", "shasum": "" }, "require": { "composer-plugin-api": "^1.0|^2.0", - "php": ">=8.2" + "php": ">=8.4" }, "conflict": { - "symfony/dotenv": "<6.4" + "symfony/error-handler": "<7.4" }, "require-dev": { "composer/composer": "^2.6", - "symfony/console": "^6.4|^7.0", - "symfony/dotenv": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0", + "symfony/dotenv": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0" }, "type": "composer-plugin", "extra": { @@ -13913,7 +13746,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v7.3.8" + "source": "https://github.com/symfony/runtime/tree/v8.0.1" }, "funding": [ { @@ -13933,68 +13766,58 @@ "type": "tidelift" } ], - "time": "2025-12-05T13:52:21+00:00" + "time": "2025-12-05T14:08:45+00:00" }, { "name": "symfony/security-bundle", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "03d6ba1eb048843b0b20a06eec69a681692cdd53" + "reference": "c170650a00ba724be3455852747af600a2f042b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/03d6ba1eb048843b0b20a06eec69a681692cdd53", - "reference": "03d6ba1eb048843b0b20a06eec69a681692cdd53", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/c170650a00ba724be3455852747af600a2f042b4", + "reference": "c170650a00ba724be3455852747af600a2f042b4", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.2", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^7.3", - "symfony/dependency-injection": "^6.4.11|^7.1.4", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/password-hasher": "^6.4|^7.0", - "symfony/security-core": "^7.3", - "symfony/security-csrf": "^6.4|^7.0", - "symfony/security-http": "^7.3", + "php": ">=8.4", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/password-hasher": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/security-http": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, - "conflict": { - "symfony/browser-kit": "<6.4", - "symfony/console": "<6.4", - "symfony/framework-bundle": "<6.4", - "symfony/http-client": "<6.4", - "symfony/ldap": "<6.4", - "symfony/serializer": "<6.4", - "symfony/twig-bundle": "<6.4", - "symfony/validator": "<6.4" - }, "require-dev": { - "symfony/asset": "^6.4|^7.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/form": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/ldap": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0", - "symfony/twig-bundle": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0", - "twig/twig": "^3.12", + "symfony/asset": "^7.4|^8.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/ldap": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/twig-bridge": "^7.4|^8.0", + "symfony/twig-bundle": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0", "web-token/jwt-library": "^3.3.2|^4.0" }, "type": "symfony-bundle", @@ -14023,7 +13846,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v7.3.10" + "source": "https://github.com/symfony/security-bundle/tree/v8.0.4" }, "funding": [ { @@ -14043,50 +13866,41 @@ "type": "tidelift" } ], - "time": "2026-01-10T13:54:35+00:00" + "time": "2026-01-10T13:58:55+00:00" }, { "name": "symfony/security-core", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "993e1cc5ae5a40eb4e27e3097aa7f242da14f3ec" + "reference": "c62565de41a136535ffa79a4db0373a7173b4d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/993e1cc5ae5a40eb4e27e3097aa7f242da14f3ec", - "reference": "993e1cc5ae5a40eb4e27e3097aa7f242da14f3ec", + "url": "https://api.github.com/repos/symfony/security-core/zipball/c62565de41a136535ffa79a4db0373a7173b4d02", + "reference": "c62565de41a136535ffa79a4db0373a7173b4d02", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.4", "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/password-hasher": "^6.4|^7.0", + "symfony/password-hasher": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/http-foundation": "<6.4", - "symfony/ldap": "<6.4", - "symfony/translation": "<6.4.3|>=7.0,<7.0.3", - "symfony/validator": "<6.4" - }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "psr/container": "^1.1|^2.0", "psr/log": "^1|^2|^3", - "symfony/cache": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/ldap": "^6.4|^7.0", - "symfony/string": "^6.4|^7.0", - "symfony/translation": "^6.4.3|^7.0.3", - "symfony/validator": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/ldap": "^7.4|^8.0", + "symfony/string": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -14114,7 +13928,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v7.3.10" + "source": "https://github.com/symfony/security-core/tree/v8.0.4" }, "funding": [ { @@ -14134,33 +13948,30 @@ "type": "tidelift" } ], - "time": "2026-01-14T09:00:21+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/security-csrf", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "f885e97aa97d5f892e0fb1bf6788cdd0c6015a7d" + "reference": "8be8bc615044c5911e6d15a5b0a80132068170c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/f885e97aa97d5f892e0fb1bf6788cdd0c6015a7d", - "reference": "f885e97aa97d5f892e0fb1bf6788cdd0c6015a7d", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/8be8bc615044c5911e6d15a5b0a80132068170c5", + "reference": "8be8bc615044c5911e6d15a5b0a80132068170c5", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/security-core": "^6.4|^7.0" - }, - "conflict": { - "symfony/http-foundation": "<6.4" + "php": ">=8.4", + "symfony/security-core": "^7.4|^8.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0" + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -14188,7 +13999,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v7.3.10" + "source": "https://github.com/symfony/security-csrf/tree/v8.0.4" }, "funding": [ { @@ -14208,50 +14019,45 @@ "type": "tidelift" } ], - "time": "2026-01-14T09:00:21+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/security-http", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "e38f5df17f2714505f17db2332371eb4047ab0ae" + "reference": "02f37c050db6e997052916194086d1a0a8790b8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/e38f5df17f2714505f17db2332371eb4047ab0ae", - "reference": "e38f5df17f2714505f17db2332371eb4047ab0ae", + "url": "https://api.github.com/repos/symfony/security-http/zipball/02f37c050db6e997052916194086d1a0a8790b8f", + "reference": "02f37c050db6e997052916194086d1a0a8790b8f", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/security-core": "^7.3", + "php": ">=8.4", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/clock": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/http-client-contracts": "<3.0", - "symfony/security-bundle": "<6.4", - "symfony/security-csrf": "<6.4" + "symfony/http-client-contracts": "<3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/cache": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", + "symfony/cache": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", "symfony/http-client-contracts": "^3.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", - "symfony/security-csrf": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", "web-token/jwt-library": "^3.3.2|^4.0" }, "type": "library", @@ -14280,7 +14086,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v7.3.10" + "source": "https://github.com/symfony/security-http/tree/v8.0.4" }, "funding": [ { @@ -14300,62 +14106,55 @@ "type": "tidelift" } ], - "time": "2026-01-14T09:00:21+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/serializer", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "86821ffa37b0889e111795b51017740278f8ec68" + "reference": "867a38a1927d23a503f7248aa182032c6ea42702" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/86821ffa37b0889e111795b51017740278f8ec68", - "reference": "86821ffa37b0889e111795b51017740278f8ec68", + "url": "https://api.github.com/repos/symfony/serializer/zipball/867a38a1927d23a503f7248aa182032c6ea42702", + "reference": "867a38a1927d23a503f7248aa182032c6ea42702", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php84": "^1.30" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<6.4", - "symfony/property-access": "<6.4", - "symfony/property-info": "<6.4", - "symfony/uid": "<6.4", - "symfony/validator": "<6.4", - "symfony/yaml": "<6.4" + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/property-info": "<7.3" }, "require-dev": { - "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "phpdocumentor/reflection-docblock": "^5.2", "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", - "symfony/cache": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^7.2", - "symfony/error-handler": "^6.4|^7.0", - "symfony/filesystem": "^6.4|^7.0", - "symfony/form": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", + "symfony/cache": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/filesystem": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/type-info": "^7.1.8", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/type-info": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -14383,7 +14182,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.3.10" + "source": "https://github.com/symfony/serializer/tree/v8.0.5" }, "funding": [ { @@ -14403,7 +14202,7 @@ "type": "tidelift" } ], - "time": "2026-01-23T10:44:29+00:00" + "time": "2026-01-27T09:06:43+00:00" }, { "name": "symfony/service-contracts", @@ -14494,20 +14293,20 @@ }, { "name": "symfony/stopwatch", - "version": "v7.3.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" + "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/67df1914c6ccd2d7b52f70d40cf2aea02159d942", + "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -14536,7 +14335,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v8.0.0" }, "funding": [ { @@ -14547,43 +14346,47 @@ "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-02-24T10:49:57+00:00" + "time": "2025-08-04T07:36:47+00:00" }, { "name": "symfony/string", - "version": "v7.3.8", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "0b1f55d79b9effb940d376799dba7cf6f2dee420" + "reference": "758b372d6882506821ed666032e43020c4f57194" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/0b1f55d79b9effb940d376799dba7cf6f2dee420", - "reference": "0b1f55d79b9effb940d376799dba7cf6f2dee420", + "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", + "reference": "758b372d6882506821ed666032e43020c4f57194", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -14622,7 +14425,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.8" + "source": "https://github.com/symfony/string/tree/v8.0.4" }, "funding": [ { @@ -14642,38 +14445,31 @@ "type": "tidelift" } ], - "time": "2025-11-26T15:55:45+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symfony/translation", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "3d2b54fe5a17110022204a1dee79ace0f375dd00" + "reference": "db70c8ce7db74fd2da7b1d268db46b2a8ce32c10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/3d2b54fe5a17110022204a1dee79ace0f375dd00", - "reference": "3d2b54fe5a17110022204a1dee79ace0f375dd00", + "url": "https://api.github.com/repos/symfony/translation/zipball/db70c8ce7db74fd2da7b1d268db46b2a8ce32c10", + "reference": "db70c8ce7db74fd2da7b1d268db46b2a8ce32c10", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation-contracts": "^3.6.1" }, "conflict": { "nikic/php-parser": "<5.0", - "symfony/config": "<6.4", - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<6.4", - "symfony/service-contracts": "<2.5", - "symfony/twig-bundle": "<6.4", - "symfony/yaml": "<6.4" + "symfony/service-contracts": "<2.5" }, "provide": { "symfony/translation-implementation": "2.3|3.0" @@ -14681,17 +14477,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", + "symfony/routing": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -14722,7 +14518,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.10" + "source": "https://github.com/symfony/translation/tree/v8.0.4" }, "funding": [ { @@ -14742,7 +14538,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:28:39+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/translation-contracts", @@ -14828,67 +14624,59 @@ }, { "name": "symfony/twig-bridge", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "fc3488f4acadb45bd0b2d651b305731719c0369a" + "reference": "3e60c35cb47b1077524c066ec277eaf92cdc2393" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/fc3488f4acadb45bd0b2d651b305731719c0369a", - "reference": "fc3488f4acadb45bd0b2d651b305731719c0369a", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/3e60c35cb47b1077524c066ec277eaf92cdc2393", + "reference": "3e60c35cb47b1077524c066ec277eaf92cdc2393", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.4", "symfony/translation-contracts": "^2.5|^3", "twig/twig": "^3.21" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/console": "<6.4", - "symfony/form": "<6.4.32|>7,<7.3.10|>7.4,<7.4.4", - "symfony/http-foundation": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/mime": "<6.4", - "symfony/serializer": "<6.4", - "symfony/translation": "<6.4", - "symfony/workflow": "<6.4" + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/form": "<7.4.4|>8.0,<8.0.4" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^6.4|^7.0", - "symfony/asset-mapper": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/emoji": "^7.1", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/form": "^6.4.32|~7.3.10|^7.4.4", - "symfony/html-sanitizer": "^6.4|^7.0", - "symfony/http-foundation": "^7.3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", + "phpdocumentor/reflection-docblock": "^5.2", + "symfony/asset": "^7.4|^8.0", + "symfony/asset-mapper": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/form": "^7.4.4|^8.0.4", + "symfony/html-sanitizer": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/polyfill-intl-icu": "^1.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^6.4|^7.0", - "symfony/security-csrf": "^6.4|^7.0", - "symfony/security-http": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/web-link": "^6.4|^7.0", - "symfony/workflow": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/security-http": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/web-link": "^7.4|^8.0", + "symfony/workflow": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0", "twig/cssinliner-extra": "^3", "twig/inky-extra": "^3", "twig/markdown-extra": "^3" @@ -14919,7 +14707,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.3.10" + "source": "https://github.com/symfony/twig-bridge/tree/v8.0.5" }, "funding": [ { @@ -14939,47 +14727,43 @@ "type": "tidelift" } ], - "time": "2026-01-04T11:12:10+00:00" + "time": "2026-01-27T09:06:10+00:00" }, { "name": "symfony/twig-bundle", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "5dfe33abdd85e23e6297a03dc4afa67d0142ae9a" + "reference": "5a68f2e0e06996514bf04900c3982b93b42487af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/5dfe33abdd85e23e6297a03dc4afa67d0142ae9a", - "reference": "5dfe33abdd85e23e6297a03dc4afa67d0142ae9a", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/5a68f2e0e06996514bf04900c3982b93b42487af", + "reference": "5a68f2e0e06996514bf04900c3982b93b42487af", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", - "php": ">=8.2", - "symfony/config": "^7.3", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/twig-bridge": "^7.3", - "twig/twig": "^3.12" - }, - "conflict": { - "symfony/framework-bundle": "<6.4", - "symfony/translation": "<6.4" + "php": ">=8.4", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/twig-bridge": "^7.4|^8.0" }, "require-dev": { - "symfony/asset": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/form": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/web-link": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/asset": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/web-link": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -15007,7 +14791,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v7.3.10" + "source": "https://github.com/symfony/twig-bundle/tree/v8.0.4" }, "funding": [ { @@ -15027,26 +14811,25 @@ "type": "tidelift" } ], - "time": "2026-01-06T12:19:16+00:00" + "time": "2026-01-06T12:43:21+00:00" }, { "name": "symfony/type-info", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "7fe70bebb370c48a034cee53d174db5dff081103" + "reference": "106a2d3bbf0d4576b2f70e6ca866fa420956ed0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/7fe70bebb370c48a034cee53d174db5dff081103", - "reference": "7fe70bebb370c48a034cee53d174db5dff081103", + "url": "https://api.github.com/repos/symfony/type-info/zipball/106a2d3bbf0d4576b2f70e6ca866fa420956ed0d", + "reference": "106a2d3bbf0d4576b2f70e6ca866fa420956ed0d", "shasum": "" }, "require": { - "php": ">=8.2", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=8.4", + "psr/container": "^1.1|^2.0" }, "conflict": { "phpstan/phpdoc-parser": "<1.30" @@ -15090,7 +14873,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v7.3.10" + "source": "https://github.com/symfony/type-info/tree/v8.0.4" }, "funding": [ { @@ -15110,28 +14893,28 @@ "type": "tidelift" } ], - "time": "2026-01-08T15:19:42+00:00" + "time": "2026-01-09T12:15:10+00:00" }, { "name": "symfony/uid", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "ae208d31706a608492ec09af9075dfcdb682be52" + "reference": "8b81bd3700f5c1913c22a3266a647aa1bb974435" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/ae208d31706a608492ec09af9075dfcdb682be52", - "reference": "ae208d31706a608492ec09af9075dfcdb682be52", + "url": "https://api.github.com/repos/symfony/uid/zipball/8b81bd3700f5c1913c22a3266a647aa1bb974435", + "reference": "8b81bd3700f5c1913c22a3266a647aa1bb974435", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -15168,7 +14951,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.10" + "source": "https://github.com/symfony/uid/tree/v8.0.4" }, "funding": [ { @@ -15188,60 +14971,52 @@ "type": "tidelift" } ], - "time": "2026-01-03T23:21:50+00:00" + "time": "2026-01-03T23:40:55+00:00" }, { "name": "symfony/validator", - "version": "v7.3.10", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "3c7782240ef932b60e73e0ab4d4180bfcf9114bf" + "reference": "ba171e89ee2d01c24c1d8201d59ec595ef4adba1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/3c7782240ef932b60e73e0ab4d4180bfcf9114bf", - "reference": "3c7782240ef932b60e73e0ab4d4180bfcf9114bf", + "url": "https://api.github.com/repos/symfony/validator/zipball/ba171e89ee2d01c24c1d8201d59ec595ef4adba1", + "reference": "ba171e89ee2d01c24c1d8201d59ec595ef4adba1", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php83": "^1.27", + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.0", "symfony/translation-contracts": "^2.5|^3" }, "conflict": { "doctrine/lexer": "<1.1", - "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<7.0", - "symfony/expression-language": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/intl": "<6.4", - "symfony/property-info": "<6.4", - "symfony/translation": "<6.4.3|>=7.0,<7.0.3", - "symfony/yaml": "<6.4" + "symfony/doctrine-bridge": "<7.4" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3|^4", - "symfony/cache": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/string": "^6.4|^7.0", - "symfony/translation": "^6.4.3|^7.0.3", - "symfony/type-info": "^7.1.8", - "symfony/yaml": "^6.4|^7.0" + "symfony/cache": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/string": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/type-info": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -15270,7 +15045,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.3.10" + "source": "https://github.com/symfony/validator/tree/v8.0.5" }, "funding": [ { @@ -15290,35 +15065,35 @@ "type": "tidelift" } ], - "time": "2026-01-08T16:18:17+00:00" + "time": "2026-01-27T09:06:10+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "3649e629f954658188eb1a83b616fb5a2e5688fe" + "reference": "326e0406fc315eca57ef5740fa4a280b7a068c82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3649e629f954658188eb1a83b616fb5a2e5688fe", - "reference": "3649e629f954658188eb1a83b616fb5a2e5688fe", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/326e0406fc315eca57ef5740fa4a280b7a068c82", + "reference": "326e0406fc315eca57ef5740fa4a280b7a068c82", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { - "symfony/console": "<6.4" + "symfony/console": "<7.4", + "symfony/error-handler": "<7.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -15357,7 +15132,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.10" + "source": "https://github.com/symfony/var-dumper/tree/v8.0.4" }, "funding": [ { @@ -15377,30 +15152,29 @@ "type": "tidelift" } ], - "time": "2026-01-01T22:03:12+00:00" + "time": "2026-01-01T23:07:29+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.3.4", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4" + "reference": "7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", - "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04", + "reference": "7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=8.4" }, "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/property-access": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -15438,7 +15212,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.4" + "source": "https://github.com/symfony/var-exporter/tree/v8.0.0" }, "funding": [ { @@ -15458,34 +15232,31 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-11-05T18:53:00+00:00" }, { "name": "symfony/web-link", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/web-link.git", - "reference": "86bb576753c071769ee2644b7b362fe24e021ec0" + "reference": "0f79e9e89c4a8ecf4964cac25a12e152bcb23a99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/86bb576753c071769ee2644b7b362fe24e021ec0", - "reference": "86bb576753c071769ee2644b7b362fe24e021ec0", + "url": "https://api.github.com/repos/symfony/web-link/zipball/0f79e9e89c4a8ecf4964cac25a12e152bcb23a99", + "reference": "0f79e9e89c4a8ecf4964cac25a12e152bcb23a99", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/link": "^1.1|^2.0" }, - "conflict": { - "symfony/http-kernel": "<6.4" - }, "provide": { "psr/link-implementation": "1.0|2.0" }, "require-dev": { - "symfony/http-kernel": "^6.4|^7.0" + "symfony/http-kernel": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -15525,7 +15296,7 @@ "push" ], "support": { - "source": "https://github.com/symfony/web-link/tree/v7.3.10" + "source": "https://github.com/symfony/web-link/tree/v8.0.4" }, "funding": [ { @@ -15545,32 +15316,31 @@ "type": "tidelift" } ], - "time": "2026-01-01T22:03:12+00:00" + "time": "2026-01-01T23:07:29+00:00" }, { "name": "symfony/yaml", - "version": "v7.3.8", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "8892cb1e9925201328e19f83825bf3d2ff6c659a" + "reference": "7a1a90ba1df6e821a6b53c4cabdc32a56cabfb14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/8892cb1e9925201328e19f83825bf3d2ff6c659a", - "reference": "8892cb1e9925201328e19f83825bf3d2ff6c659a", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7a1a90ba1df6e821a6b53c4cabdc32a56cabfb14", + "reference": "7a1a90ba1df6e821a6b53c4cabdc32a56cabfb14", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", + "php": ">=8.4", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<6.4" + "symfony/console": "<7.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^7.4|^8.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -15601,7 +15371,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.8" + "source": "https://github.com/symfony/yaml/tree/v8.0.1" }, "funding": [ { @@ -15621,7 +15391,7 @@ "type": "tidelift" } ], - "time": "2025-12-04T18:07:52+00:00" + "time": "2025-12-04T18:17:06+00:00" }, { "name": "tecnickcom/tcpdf", @@ -16229,16 +15999,16 @@ }, { "name": "web-auth/webauthn-lib", - "version": "5.2.3", + "version": "5.3.x-dev", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-lib.git", - "reference": "8782f575032fedc36e2eb27c39c736054e2b6867" + "reference": "88d969b1cec56f28d16b3cb02e7f24e0a9e2f987" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/8782f575032fedc36e2eb27c39c736054e2b6867", - "reference": "8782f575032fedc36e2eb27c39c736054e2b6867", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/88d969b1cec56f28d16b3cb02e7f24e0a9e2f987", + "reference": "88d969b1cec56f28d16b3cb02e7f24e0a9e2f987", "shasum": "" }, "require": { @@ -16252,12 +16022,12 @@ "psr/log": "^1.0|^2.0|^3.0", "spomky-labs/cbor-php": "^3.0", "spomky-labs/pki-framework": "^1.0", - "symfony/clock": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^3.2", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "web-auth/cose-lib": "^4.2.3" }, "suggest": { @@ -16265,6 +16035,7 @@ "symfony/event-dispatcher": "Recommended to use dispatched events", "web-token/jwt-library": "Mandatory for fetching Metadata Statement from distant sources" }, + "default-branch": true, "type": "library", "extra": { "thanks": { @@ -16299,7 +16070,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-lib/tree/5.2.3" + "source": "https://github.com/web-auth/webauthn-lib/tree/5.3.x" }, "funding": [ { @@ -16311,7 +16082,7 @@ "type": "patreon" } ], - "time": "2025-12-20T10:54:02+00:00" + "time": "2025-11-28T07:28:42+00:00" }, { "name": "web-token/jwt-library", @@ -16529,73 +16300,6 @@ }, "time": "2024-11-21T13:46:39+00:00" }, - { - "name": "masterminds/html5", - "version": "2.10.0", - "source": { - "type": "git", - "url": "https://github.com/Masterminds/html5-php.git", - "reference": "fcf91eb64359852f00d921887b219479b4f21251" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", - "reference": "fcf91eb64359852f00d921887b219479b4f21251", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Masterminds\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matt Butcher", - "email": "technosophos@gmail.com" - }, - { - "name": "Matt Farina", - "email": "matt@mattfarina.com" - }, - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - } - ], - "description": "An HTML5 parser and serializer.", - "homepage": "http://masterminds.github.io/html5-php", - "keywords": [ - "HTML5", - "dom", - "html", - "parser", - "querypath", - "serializer", - "xml" - ], - "support": { - "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" - }, - "time": "2025-07-25T09:04:22+00:00" - }, { "name": "myclabs/deep-copy", "version": "1.13.4", @@ -16834,11 +16538,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.37", + "version": "2.1.38", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/28cd424c5ea984128c95cfa7ea658808e8954e49", - "reference": "28cd424c5ea984128c95cfa7ea658808e8954e49", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629", + "reference": "dfaf1f530e1663aa167bc3e52197adb221582629", "shasum": "" }, "require": { @@ -16883,7 +16587,7 @@ "type": "github" } ], - "time": "2026-01-24T08:21:55+00:00" + "time": "2026-01-30T17:12:46+00:00" }, { "name": "phpunit/php-code-coverage", @@ -17221,16 +16925,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.5.7", + "version": "12.5.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "79dee3d2685b80518e94b9ea741b3f822b213a5e" + "reference": "37ddb96c14bfee10304825edbb7e66d341ec6889" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/79dee3d2685b80518e94b9ea741b3f822b213a5e", - "reference": "79dee3d2685b80518e94b9ea741b3f822b213a5e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/37ddb96c14bfee10304825edbb7e66d341ec6889", + "reference": "37ddb96c14bfee10304825edbb7e66d341ec6889", "shasum": "" }, "require": { @@ -17298,7 +17002,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.8" }, "funding": [ { @@ -17322,20 +17026,20 @@ "type": "tidelift" } ], - "time": "2026-01-24T16:12:53+00:00" + "time": "2026-01-27T06:12:29+00:00" }, { "name": "rector/rector", - "version": "2.3.4", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "9227d7a24b0f23ae941057509364f948d5da9ab2" + "reference": "9442f4037de6a5347ae157fe8e6c7cda9d909070" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/9227d7a24b0f23ae941057509364f948d5da9ab2", - "reference": "9227d7a24b0f23ae941057509364f948d5da9ab2", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/9442f4037de6a5347ae157fe8e6c7cda9d909070", + "reference": "9442f4037de6a5347ae157fe8e6c7cda9d909070", "shasum": "" }, "require": { @@ -17374,7 +17078,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.3.4" + "source": "https://github.com/rectorphp/rector/tree/2.3.5" }, "funding": [ { @@ -17382,7 +17086,7 @@ "type": "github" } ], - "time": "2026-01-21T14:49:03+00:00" + "time": "2026-01-28T15:22:48+00:00" }, { "name": "sebastian/cli-parser", @@ -18335,27 +18039,27 @@ }, { "name": "symfony/browser-kit", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "a1e115df7c86200f210814867a61694e6d304256" + "reference": "0d998c101e1920fc68572209d1316fec0db728ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/a1e115df7c86200f210814867a61694e6d304256", - "reference": "a1e115df7c86200f210814867a61694e6d304256", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/0d998c101e1920fc68572209d1316fec0db728ef", + "reference": "0d998c101e1920fc68572209d1316fec0db728ef", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/dom-crawler": "^6.4|^7.0" + "php": ">=8.4", + "symfony/dom-crawler": "^7.4|^8.0" }, "require-dev": { - "symfony/css-selector": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0" + "symfony/css-selector": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -18383,7 +18087,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v7.3.10" + "source": "https://github.com/symfony/browser-kit/tree/v8.0.4" }, "funding": [ { @@ -18403,24 +18107,24 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:28:39+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/css-selector", - "version": "v7.3.6", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "84321188c4754e64273b46b406081ad9b18e8614" + "reference": "6225bd458c53ecdee056214cb4a2ffaf58bd592b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/84321188c4754e64273b46b406081ad9b18e8614", - "reference": "84321188c4754e64273b46b406081ad9b18e8614", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/6225bd458c53ecdee056214cb4a2ffaf58bd592b", + "reference": "6225bd458c53ecdee056214cb4a2ffaf58bd592b", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "type": "library", "autoload": { @@ -18452,7 +18156,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.6" + "source": "https://github.com/symfony/css-selector/tree/v8.0.0" }, "funding": [ { @@ -18472,34 +18176,34 @@ "type": "tidelift" } ], - "time": "2025-10-29T17:24:25+00:00" + "time": "2025-10-30T14:17:19+00:00" }, { "name": "symfony/debug-bundle", - "version": "v7.3.5", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "0aee008fb501677fa5b62ea5f65cabcf041629ef" + "reference": "02665efd40733372a4b4bdd78722426a6f95849b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/0aee008fb501677fa5b62ea5f65cabcf041629ef", - "reference": "0aee008fb501677fa5b62ea5f65cabcf041629ef", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/02665efd40733372a4b4bdd78722426a6f95849b", + "reference": "02665efd40733372a4b4bdd78722426a6f95849b", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.2", - "symfony/config": "^7.3", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "php": ">=8.4", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/twig-bridge": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "require-dev": { - "symfony/web-profiler-bundle": "^6.4|^7.0" + "symfony/web-profiler-bundle": "^7.4|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -18527,7 +18231,7 @@ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v7.3.5" + "source": "https://github.com/symfony/debug-bundle/tree/v8.0.0" }, "funding": [ { @@ -18547,30 +18251,29 @@ "type": "tidelift" } ], - "time": "2025-10-13T11:49:56+00:00" + "time": "2025-10-24T14:30:40+00:00" }, { "name": "symfony/dom-crawler", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "8d9b47c994701cd50d3507062501c1ac2b428aaf" + "reference": "fd78228fa362b41729173183493f46b1df49485f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/8d9b47c994701cd50d3507062501c1ac2b428aaf", - "reference": "8d9b47c994701cd50d3507062501c1ac2b428aaf", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/fd78228fa362b41729173183493f46b1df49485f", + "reference": "fd78228fa362b41729173183493f46b1df49485f", "shasum": "" }, "require": { - "masterminds/html5": "^2.6", - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.0" }, "require-dev": { - "symfony/css-selector": "^6.4|^7.0" + "symfony/css-selector": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -18598,7 +18301,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.3.10" + "source": "https://github.com/symfony/dom-crawler/tree/v8.0.4" }, "funding": [ { @@ -18618,7 +18321,7 @@ "type": "tidelift" } ], - "time": "2026-01-05T08:45:46+00:00" + "time": "2026-01-05T09:27:50+00:00" }, { "name": "symfony/maker-bundle", @@ -18720,41 +18423,37 @@ }, { "name": "symfony/web-profiler-bundle", - "version": "v7.3.10", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "3f288c176f4b70d083c1b37a0b9aa0c4745b2ef3" + "reference": "0d0df8b3601f80b455d0bf40402d104c02d8b6fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/3f288c176f4b70d083c1b37a0b9aa0c4745b2ef3", - "reference": "3f288c176f4b70d083c1b37a0b9aa0c4745b2ef3", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/0d0df8b3601f80b455d0bf40402d104c02d8b6fa", + "reference": "0d0df8b3601f80b455d0bf40402d104c02d8b6fa", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", - "php": ">=8.2", - "symfony/config": "^7.3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/routing": "^6.4|^7.0", - "symfony/twig-bundle": "^6.4|^7.0", - "twig/twig": "^3.12" + "php": ">=8.4", + "symfony/config": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/twig-bundle": "^7.4|^8.0" }, "conflict": { - "symfony/form": "<6.4", - "symfony/mailer": "<6.4", - "symfony/messenger": "<6.4", - "symfony/serializer": "<7.2", - "symfony/workflow": "<7.3" + "symfony/serializer": "<7.4", + "symfony/workflow": "<7.4" }, "require-dev": { - "symfony/browser-kit": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/browser-kit": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -18785,7 +18484,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.3.10" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v8.0.4" }, "funding": [ { @@ -18805,7 +18504,7 @@ "type": "tidelift" } ], - "time": "2026-01-07T10:03:30+00:00" + "time": "2026-01-07T12:23:22+00:00" }, { "name": "theseer/tokenizer", @@ -18860,7 +18559,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "web-auth/webauthn-lib": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index dead5a8..d9f2990 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -7,11 +7,7 @@ doctrine: #server_version: '16' profiling_collect_backtrace: '%kernel.debug%' - use_savepoints: true orm: - auto_generate_proxy_classes: false - enable_native_lazy_objects: true - report_fields_where_declared: true validate_xml_mapping: true naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware identity_generation_preferences: @@ -24,8 +20,6 @@ doctrine: dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App - controller_resolver: - auto_mapping: false when@test: doctrine: @@ -36,8 +30,6 @@ when@test: when@prod: doctrine: orm: - auto_generate_proxy_classes: false - proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' query_cache_driver: type: pool pool: doctrine.system_cache_pool diff --git a/config/packages/pwa.yaml b/config/packages/pwa.yaml index a154c5b..5640daa 100644 --- a/config/packages/pwa.yaml +++ b/config/packages/pwa.yaml @@ -27,7 +27,8 @@ pwa: cache_prefix: 'goolge-fonts' max_entries: 20 max_age: 1 - use_cdn: false + config: + use_cdn: false manifest: enabled: true name: "Réservation Lukikevent" diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 728f418..91c1a3e 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -69,7 +69,10 @@ security: main: pattern: ^/ provider: reserve_account_provider # Force l'entité Customer ici - custom_authenticator: App\Security\CustomerAuthenticator + entry_point: App\Security\CustomerAuthenticator # Spécifie l'authentificateur à utiliser comme point d'entrée + custom_authenticator: + - App\Security\CustomerAuthenticator + - App\Security\FlowAuthenticator user_checker: App\Security\UserChecker # Si vous voulez vérifier l'activation du compte logout: path: reservation_logout diff --git a/config/reference.php b/config/reference.php index 459b86a..ba7931c 100644 --- a/config/reference.php +++ b/config/reference.php @@ -4,6 +4,8 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\Config\Loader\ParamConfigurator as Param; + /** * This class provides array-shapes for configuring the services and bundles of an application. * @@ -31,7 +33,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * type?: string|null, * ignore_errors?: bool, * }> - * @psalm-type ParametersConfig = array|null>|null> + * @psalm-type ParametersConfig = array|Param|null>|Param|null> * @psalm-type ArgumentsType = list|array * @psalm-type CallType = array|array{0:string, 1?:ArgumentsType, 2?:bool}|array{method:string, arguments?:ArgumentsType, returns_clone?:bool} * @psalm-type TagsType = list>> // arrays inside the list must have only one element, with the tag name as the key @@ -124,1390 +126,2316 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * } * @psalm-type ExtensionType = array * @psalm-type FrameworkConfig = array{ - * secret?: scalar|null, - * http_method_override?: bool, // Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. // Default: false - * allowed_http_method_override?: list|null, - * trust_x_sendfile_type_header?: scalar|null, // Set true to enable support for xsendfile in binary file responses. // Default: "%env(bool:default::SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER)%" - * ide?: scalar|null, // Default: "%env(default::SYMFONY_IDE)%" - * test?: bool, - * default_locale?: scalar|null, // Default: "en" - * set_locale_from_accept_language?: bool, // Whether to use the Accept-Language HTTP header to set the Request locale (only when the "_locale" request attribute is not passed). // Default: false - * set_content_language_from_locale?: bool, // Whether to set the Content-Language HTTP header on the Response using the Request locale. // Default: false - * enabled_locales?: list, - * trusted_hosts?: list, + * secret?: scalar|Param|null, + * http_method_override?: bool|Param, // Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. // Default: false + * allowed_http_method_override?: list|null, + * trust_x_sendfile_type_header?: scalar|Param|null, // Set true to enable support for xsendfile in binary file responses. // Default: "%env(bool:default::SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER)%" + * ide?: scalar|Param|null, // Default: "%env(default::SYMFONY_IDE)%" + * test?: bool|Param, + * default_locale?: scalar|Param|null, // Default: "en" + * set_locale_from_accept_language?: bool|Param, // Whether to use the Accept-Language HTTP header to set the Request locale (only when the "_locale" request attribute is not passed). // Default: false + * set_content_language_from_locale?: bool|Param, // Whether to set the Content-Language HTTP header on the Response using the Request locale. // Default: false + * enabled_locales?: list, + * trusted_hosts?: list, * trusted_proxies?: mixed, // Default: ["%env(default::SYMFONY_TRUSTED_PROXIES)%"] - * trusted_headers?: list, - * error_controller?: scalar|null, // Default: "error_controller" - * handle_all_throwables?: bool, // HttpKernel will handle all kinds of \Throwable. // Default: true + * trusted_headers?: list, + * error_controller?: scalar|Param|null, // Default: "error_controller" + * handle_all_throwables?: bool|Param, // HttpKernel will handle all kinds of \Throwable. // Default: true * csrf_protection?: bool|array{ - * enabled?: scalar|null, // Default: null - * stateless_token_ids?: list, - * check_header?: scalar|null, // Whether to check the CSRF token in a header in addition to a cookie when using stateless protection. // Default: false - * cookie_name?: scalar|null, // The name of the cookie to use when using stateless protection. // Default: "csrf-token" + * enabled?: scalar|Param|null, // Default: null + * stateless_token_ids?: list, + * check_header?: scalar|Param|null, // Whether to check the CSRF token in a header in addition to a cookie when using stateless protection. // Default: false + * cookie_name?: scalar|Param|null, // The name of the cookie to use when using stateless protection. // Default: "csrf-token" * }, * form?: bool|array{ // Form configuration - * enabled?: bool, // Default: true - * csrf_protection?: array{ - * enabled?: scalar|null, // Default: null - * token_id?: scalar|null, // Default: null - * field_name?: scalar|null, // Default: "_token" - * field_attr?: array, + * enabled?: bool|Param, // Default: true + * csrf_protection?: bool|array{ + * enabled?: scalar|Param|null, // Default: null + * token_id?: scalar|Param|null, // Default: null + * field_name?: scalar|Param|null, // Default: "_token" + * field_attr?: array, * }, * }, * http_cache?: bool|array{ // HTTP cache configuration - * enabled?: bool, // Default: false - * debug?: bool, // Default: "%kernel.debug%" - * trace_level?: "none"|"short"|"full", - * trace_header?: scalar|null, - * default_ttl?: int, - * private_headers?: list, - * skip_response_headers?: list, - * allow_reload?: bool, - * allow_revalidate?: bool, - * stale_while_revalidate?: int, - * stale_if_error?: int, - * terminate_on_cache_hit?: bool, + * enabled?: bool|Param, // Default: false + * debug?: bool|Param, // Default: "%kernel.debug%" + * trace_level?: "none"|"short"|"full"|Param, + * trace_header?: scalar|Param|null, + * default_ttl?: int|Param, + * private_headers?: list, + * skip_response_headers?: list, + * allow_reload?: bool|Param, + * allow_revalidate?: bool|Param, + * stale_while_revalidate?: int|Param, + * stale_if_error?: int|Param, + * terminate_on_cache_hit?: bool|Param, * }, * esi?: bool|array{ // ESI configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * ssi?: bool|array{ // SSI configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * fragments?: bool|array{ // Fragments configuration - * enabled?: bool, // Default: false - * hinclude_default_template?: scalar|null, // Default: null - * path?: scalar|null, // Default: "/_fragment" + * enabled?: bool|Param, // Default: false + * hinclude_default_template?: scalar|Param|null, // Default: null + * path?: scalar|Param|null, // Default: "/_fragment" * }, * profiler?: bool|array{ // Profiler configuration - * enabled?: bool, // Default: false - * collect?: bool, // Default: true - * collect_parameter?: scalar|null, // The name of the parameter to use to enable or disable collection on a per request basis. // Default: null - * only_exceptions?: bool, // Default: false - * only_main_requests?: bool, // Default: false - * dsn?: scalar|null, // Default: "file:%kernel.cache_dir%/profiler" - * collect_serializer_data?: bool, // Enables the serializer data collector and profiler panel. // Default: false + * enabled?: bool|Param, // Default: false + * collect?: bool|Param, // Default: true + * collect_parameter?: scalar|Param|null, // The name of the parameter to use to enable or disable collection on a per request basis. // Default: null + * only_exceptions?: bool|Param, // Default: false + * only_main_requests?: bool|Param, // Default: false + * dsn?: scalar|Param|null, // Default: "file:%kernel.cache_dir%/profiler" + * collect_serializer_data?: true|Param, // Default: true * }, * workflows?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * workflows?: array, - * definition_validators?: list, - * support_strategy?: scalar|null, - * initial_marking?: list, - * events_to_dispatch?: list|null, + * supports?: list, + * definition_validators?: list, + * support_strategy?: scalar|Param|null, + * initial_marking?: list, + * events_to_dispatch?: list|null, * places?: list, * }>, * transitions: list, * to?: list, - * weight?: int, // Default: 1 + * weight?: int|Param, // Default: 1 * metadata?: list, * }>, * metadata?: list, * }>, * }, * router?: bool|array{ // Router configuration - * enabled?: bool, // Default: false - * resource: scalar|null, - * type?: scalar|null, - * cache_dir?: scalar|null, // Deprecated: Setting the "framework.router.cache_dir.cache_dir" configuration option is deprecated. It will be removed in version 8.0. // Default: "%kernel.build_dir%" - * default_uri?: scalar|null, // The default URI used to generate URLs in a non-HTTP context. // Default: null - * http_port?: scalar|null, // Default: 80 - * https_port?: scalar|null, // Default: 443 - * strict_requirements?: scalar|null, // set to true to throw an exception when a parameter does not match the requirements set to false to disable exceptions when a parameter does not match the requirements (and return null instead) set to null to disable parameter checks against requirements 'true' is the preferred configuration in development mode, while 'false' or 'null' might be preferred in production // Default: true - * utf8?: bool, // Default: true + * enabled?: bool|Param, // Default: false + * resource: scalar|Param|null, + * type?: scalar|Param|null, + * default_uri?: scalar|Param|null, // The default URI used to generate URLs in a non-HTTP context. // Default: null + * http_port?: scalar|Param|null, // Default: 80 + * https_port?: scalar|Param|null, // Default: 443 + * strict_requirements?: scalar|Param|null, // set to true to throw an exception when a parameter does not match the requirements set to false to disable exceptions when a parameter does not match the requirements (and return null instead) set to null to disable parameter checks against requirements 'true' is the preferred configuration in development mode, while 'false' or 'null' might be preferred in production // Default: true + * utf8?: bool|Param, // Default: true * }, * session?: bool|array{ // Session configuration - * enabled?: bool, // Default: false - * storage_factory_id?: scalar|null, // Default: "session.storage.factory.native" - * handler_id?: scalar|null, // Defaults to using the native session handler, or to the native *file* session handler if "save_path" is not null. - * name?: scalar|null, - * cookie_lifetime?: scalar|null, - * cookie_path?: scalar|null, - * cookie_domain?: scalar|null, - * cookie_secure?: true|false|"auto", // Default: "auto" - * cookie_httponly?: bool, // Default: true - * cookie_samesite?: null|"lax"|"strict"|"none", // Default: "lax" - * use_cookies?: bool, - * gc_divisor?: scalar|null, - * gc_probability?: scalar|null, - * gc_maxlifetime?: scalar|null, - * save_path?: scalar|null, // Defaults to "%kernel.cache_dir%/sessions" if the "handler_id" option is not null. - * metadata_update_threshold?: int, // Seconds to wait between 2 session metadata updates. // Default: 0 - * sid_length?: int, // Deprecated: Setting the "framework.session.sid_length.sid_length" configuration option is deprecated. It will be removed in version 8.0. No alternative is provided as PHP 8.4 has deprecated the related option. - * sid_bits_per_character?: int, // Deprecated: Setting the "framework.session.sid_bits_per_character.sid_bits_per_character" configuration option is deprecated. It will be removed in version 8.0. No alternative is provided as PHP 8.4 has deprecated the related option. + * enabled?: bool|Param, // Default: false + * storage_factory_id?: scalar|Param|null, // Default: "session.storage.factory.native" + * handler_id?: scalar|Param|null, // Defaults to using the native session handler, or to the native *file* session handler if "save_path" is not null. + * name?: scalar|Param|null, + * cookie_lifetime?: scalar|Param|null, + * cookie_path?: scalar|Param|null, + * cookie_domain?: scalar|Param|null, + * cookie_secure?: true|false|"auto"|Param, // Default: "auto" + * cookie_httponly?: bool|Param, // Default: true + * cookie_samesite?: null|"lax"|"strict"|"none"|Param, // Default: "lax" + * use_cookies?: bool|Param, + * gc_divisor?: scalar|Param|null, + * gc_probability?: scalar|Param|null, + * gc_maxlifetime?: scalar|Param|null, + * save_path?: scalar|Param|null, // Defaults to "%kernel.cache_dir%/sessions" if the "handler_id" option is not null. + * metadata_update_threshold?: int|Param, // Seconds to wait between 2 session metadata updates. // Default: 0 * }, * request?: bool|array{ // Request configuration - * enabled?: bool, // Default: false - * formats?: array>, + * enabled?: bool|Param, // Default: false + * formats?: array>, * }, * assets?: bool|array{ // Assets configuration - * enabled?: bool, // Default: true - * strict_mode?: bool, // Throw an exception if an entry is missing from the manifest.json. // Default: false - * version_strategy?: scalar|null, // Default: null - * version?: scalar|null, // Default: null - * version_format?: scalar|null, // Default: "%%s?%%s" - * json_manifest_path?: scalar|null, // Default: null - * base_path?: scalar|null, // Default: "" - * base_urls?: list, + * enabled?: bool|Param, // Default: true + * 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, // Default: null + * version_format?: scalar|Param|null, // Default: "%%s?%%s" + * json_manifest_path?: scalar|Param|null, // Default: null + * base_path?: scalar|Param|null, // Default: "" + * base_urls?: 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?: list, * }>, * }, * asset_mapper?: bool|array{ // Asset Mapper configuration - * enabled?: bool, // Default: true - * paths?: array, - * excluded_patterns?: list, - * exclude_dotfiles?: bool, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true - * server?: bool, // If true, a "dev server" will return the assets from the public directory (true in "debug" mode only by default). // Default: true - * public_prefix?: scalar|null, // The public path where the assets will be written to (and served from when "server" is true). // Default: "/assets/" - * missing_import_mode?: "strict"|"warn"|"ignore", // Behavior if an asset cannot be found when imported from JavaScript or CSS files - e.g. "import './non-existent.js'". "strict" means an exception is thrown, "warn" means a warning is logged, "ignore" means the import is left as-is. // Default: "warn" - * extensions?: array, - * importmap_path?: scalar|null, // The path of the importmap.php file. // Default: "%kernel.project_dir%/importmap.php" - * importmap_polyfill?: scalar|null, // The importmap name that will be used to load the polyfill. Set to false to disable. // Default: "es-module-shims" - * importmap_script_attributes?: array, - * vendor_dir?: scalar|null, // The directory to store JavaScript vendors. // Default: "%kernel.project_dir%/assets/vendor" + * enabled?: bool|Param, // Default: true + * paths?: array, + * excluded_patterns?: list, + * exclude_dotfiles?: bool|Param, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true + * server?: bool|Param, // If true, a "dev server" will return the assets from the public directory (true in "debug" mode only by default). // Default: true + * public_prefix?: scalar|Param|null, // The public path where the assets will be written to (and served from when "server" is true). // Default: "/assets/" + * missing_import_mode?: "strict"|"warn"|"ignore"|Param, // Behavior if an asset cannot be found when imported from JavaScript or CSS files - e.g. "import './non-existent.js'". "strict" means an exception is thrown, "warn" means a warning is logged, "ignore" means the import is left as-is. // Default: "warn" + * extensions?: array, + * importmap_path?: scalar|Param|null, // The path of the importmap.php file. // Default: "%kernel.project_dir%/importmap.php" + * importmap_polyfill?: scalar|Param|null, // The importmap name that will be used to load the polyfill. Set to false to disable. // Default: "es-module-shims" + * importmap_script_attributes?: array, + * vendor_dir?: scalar|Param|null, // The directory to store JavaScript vendors. // Default: "%kernel.project_dir%/assets/vendor" * precompress?: bool|array{ // Precompress assets with Brotli, Zstandard and gzip. - * enabled?: bool, // Default: false - * formats?: list, - * extensions?: list, + * enabled?: bool|Param, // Default: false + * formats?: list, + * extensions?: list, * }, * }, * translator?: bool|array{ // Translator configuration - * enabled?: bool, // Default: true - * fallbacks?: list, - * logging?: bool, // Default: false - * formatter?: scalar|null, // Default: "translator.formatter.default" - * cache_dir?: scalar|null, // Default: "%kernel.cache_dir%/translations" - * default_path?: scalar|null, // The default path used to load translations. // Default: "%kernel.project_dir%/translations" - * paths?: list, + * enabled?: bool|Param, // Default: true + * fallbacks?: list, + * logging?: bool|Param, // Default: false + * formatter?: scalar|Param|null, // Default: "translator.formatter.default" + * cache_dir?: scalar|Param|null, // Default: "%kernel.cache_dir%/translations" + * default_path?: scalar|Param|null, // The default path used to load translations. // Default: "%kernel.project_dir%/translations" + * paths?: list, * pseudo_localization?: bool|array{ - * enabled?: bool, // Default: false - * accents?: bool, // Default: true - * expansion_factor?: float, // Default: 1.0 - * brackets?: bool, // Default: true - * parse_html?: bool, // Default: false - * localizable_html_attributes?: list, + * enabled?: bool|Param, // Default: false + * accents?: bool|Param, // Default: true + * expansion_factor?: float|Param, // Default: 1.0 + * brackets?: bool|Param, // Default: true + * parse_html?: bool|Param, // Default: false + * localizable_html_attributes?: list, * }, * providers?: array, - * locales?: list, + * dsn?: scalar|Param|null, + * domains?: list, + * locales?: list, * }>, * globals?: array, - * domain?: string, + * message?: string|Param, + * parameters?: array, + * domain?: string|Param, * }>, * }, * validation?: bool|array{ // Validation configuration - * enabled?: bool, // Default: true - * cache?: scalar|null, // Deprecated: Setting the "framework.validation.cache.cache" configuration option is deprecated. It will be removed in version 8.0. - * enable_attributes?: bool, // Default: true - * static_method?: list, - * translation_domain?: scalar|null, // Default: "validators" - * email_validation_mode?: "html5"|"html5-allow-no-tld"|"strict"|"loose", // Default: "html5" + * enabled?: bool|Param, // Default: true + * enable_attributes?: bool|Param, // Default: true + * static_method?: list, + * translation_domain?: scalar|Param|null, // Default: "validators" + * email_validation_mode?: "html5"|"html5-allow-no-tld"|"strict"|Param, // Default: "html5" * mapping?: array{ - * paths?: list, + * paths?: list, * }, * not_compromised_password?: bool|array{ - * enabled?: bool, // When disabled, compromised passwords will be accepted as valid. // Default: true - * endpoint?: scalar|null, // API endpoint for the NotCompromisedPassword Validator. // Default: null + * enabled?: bool|Param, // When disabled, compromised passwords will be accepted as valid. // Default: true + * endpoint?: scalar|Param|null, // API endpoint for the NotCompromisedPassword Validator. // Default: null * }, - * disable_translation?: bool, // Default: false + * disable_translation?: bool|Param, // Default: false * auto_mapping?: array, + * services?: list, * }>, * }, - * annotations?: bool|array{ - * enabled?: bool, // Default: false - * }, * serializer?: bool|array{ // Serializer configuration - * enabled?: bool, // Default: true - * enable_attributes?: bool, // Default: true - * name_converter?: scalar|null, - * circular_reference_handler?: scalar|null, - * max_depth_handler?: scalar|null, + * enabled?: bool|Param, // Default: true + * enable_attributes?: bool|Param, // Default: true + * name_converter?: scalar|Param|null, + * circular_reference_handler?: scalar|Param|null, + * max_depth_handler?: scalar|Param|null, * mapping?: array{ - * paths?: list, + * paths?: list, * }, * default_context?: list, * named_serializers?: array, - * include_built_in_normalizers?: bool, // Whether to include the built-in normalizers // Default: true - * include_built_in_encoders?: bool, // Whether to include the built-in encoders // Default: true + * 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, // Default: true - * magic_call?: bool, // Default: false - * magic_get?: bool, // Default: true - * magic_set?: bool, // Default: true - * throw_exception_on_invalid_index?: bool, // Default: false - * throw_exception_on_invalid_property_path?: bool, // Default: true + * enabled?: bool|Param, // Default: true + * magic_call?: bool|Param, // Default: false + * magic_get?: bool|Param, // Default: true + * magic_set?: bool|Param, // Default: true + * throw_exception_on_invalid_index?: bool|Param, // Default: false + * throw_exception_on_invalid_property_path?: bool|Param, // Default: true * }, * type_info?: bool|array{ // Type info configuration - * enabled?: bool, // Default: true - * aliases?: array, + * enabled?: bool|Param, // Default: true + * aliases?: array, * }, * property_info?: bool|array{ // Property info configuration - * enabled?: bool, // Default: true - * with_constructor_extractor?: bool, // Registers the constructor extractor. + * enabled?: bool|Param, // Default: true + * with_constructor_extractor?: bool|Param, // Registers the constructor extractor. // Default: true * }, * cache?: array{ // Cache configuration - * prefix_seed?: scalar|null, // Used to namespace cache keys when using several apps with the same shared backend. // Default: "_%kernel.project_dir%.%kernel.container_class%" - * app?: scalar|null, // App related cache pools configuration. // Default: "cache.adapter.filesystem" - * system?: scalar|null, // System related cache pools configuration. // Default: "cache.adapter.system" - * directory?: scalar|null, // Default: "%kernel.share_dir%/pools/app" - * default_psr6_provider?: scalar|null, - * default_redis_provider?: scalar|null, // Default: "redis://localhost" - * default_valkey_provider?: scalar|null, // Default: "valkey://localhost" - * default_memcached_provider?: scalar|null, // Default: "memcached://localhost" - * default_doctrine_dbal_provider?: scalar|null, // Default: "database_connection" - * default_pdo_provider?: scalar|null, // Default: null + * prefix_seed?: scalar|Param|null, // Used to namespace cache keys when using several apps with the same shared backend. // Default: "_%kernel.project_dir%.%kernel.container_class%" + * app?: scalar|Param|null, // App related cache pools configuration. // Default: "cache.adapter.filesystem" + * system?: scalar|Param|null, // System related cache pools configuration. // Default: "cache.adapter.system" + * directory?: scalar|Param|null, // Default: "%kernel.share_dir%/pools/app" + * default_psr6_provider?: scalar|Param|null, + * default_redis_provider?: scalar|Param|null, // Default: "redis://localhost" + * default_valkey_provider?: scalar|Param|null, // Default: "valkey://localhost" + * default_memcached_provider?: scalar|Param|null, // Default: "memcached://localhost" + * default_doctrine_dbal_provider?: scalar|Param|null, // Default: "database_connection" + * default_pdo_provider?: scalar|Param|null, // Default: null * pools?: array, - * tags?: scalar|null, // Default: null - * public?: bool, // Default: false - * default_lifetime?: scalar|null, // Default lifetime of the pool. - * provider?: scalar|null, // Overwrite the setting from the default provider for this adapter. - * early_expiration_message_bus?: scalar|null, - * clearer?: scalar|null, + * adapters?: 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, // Throw PHP errors as \ErrorException instances. // Default: true + * throw?: bool|Param, // Throw PHP errors as \ErrorException instances. // Default: true * }, * exceptions?: array, * web_link?: bool|array{ // Web links configuration - * enabled?: bool, // Default: true + * enabled?: bool|Param, // Default: true * }, * lock?: bool|string|array{ // Lock configuration - * enabled?: bool, // Default: false - * resources?: array>, + * enabled?: bool|Param, // Default: false + * resources?: array>, * }, * semaphore?: bool|string|array{ // Semaphore configuration - * enabled?: bool, // Default: false - * resources?: array, + * enabled?: bool|Param, // Default: false + * resources?: array, * }, * messenger?: bool|array{ // Messenger configuration - * enabled?: bool, // Default: true + * enabled?: bool|Param, // Default: true * routing?: array, + * senders?: list, * }>, * serializer?: array{ - * default_serializer?: scalar|null, // Service id to use as the default serializer for the transports. // Default: "messenger.transport.native_php_serializer" + * 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{ - * format?: scalar|null, // Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default). // Default: "json" + * format?: scalar|Param|null, // Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default). // Default: "json" * context?: array, * }, * }, * transports?: array, - * failure_transport?: scalar|null, // Transport name to send failed messages to (after all retries have failed). // Default: null + * 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|null, // Service id to override the retry strategy entirely. // Default: null - * max_retries?: int, // Default: 3 - * delay?: int, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 - * multiplier?: float, // If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries)). // Default: 2 - * max_delay?: int, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 - * jitter?: float, // Randomness to apply to the delay (between 0 and 1). // Default: 0.1 + * 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|null, // Rate limiter name to use when processing messages. // Default: null + * rate_limiter?: scalar|Param|null, // Rate limiter name to use when processing messages. // Default: null * }>, - * failure_transport?: scalar|null, // Transport name to send failed messages to (after all retries have failed). // Default: null - * stop_worker_on_signals?: list, - * default_bus?: scalar|null, // 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?: list, + * default_bus?: scalar|Param|null, // Default: null * buses?: array, * }>, * }>, * }, * scheduler?: bool|array{ // Scheduler configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, - * disallow_search_engine_index?: bool, // Enabled by default when debug is enabled. // Default: true + * disallow_search_engine_index?: bool|Param, // Enabled by default when debug is enabled. // Default: true * http_client?: bool|array{ // HTTP Client configuration - * enabled?: bool, // Default: true - * max_host_connections?: int, // The maximum number of connections to a single host. + * enabled?: bool|Param, // Default: true + * max_host_connections?: int|Param, // The maximum number of connections to a single host. * default_options?: array{ * headers?: array, * vars?: array, - * max_redirects?: int, // The maximum number of redirects to follow. - * http_version?: scalar|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. - * resolve?: array, - * proxy?: scalar|null, // The URL of the proxy to pass requests through or null for automatic detection. - * no_proxy?: scalar|null, // A comma separated list of hosts that do not require a proxy to be reached. - * timeout?: float, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. - * max_duration?: float, // The maximum execution time for the request+response as a whole. - * bindto?: scalar|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. - * verify_peer?: bool, // Indicates if the peer should be verified in a TLS context. - * verify_host?: bool, // Indicates if the host should exist as a certificate common name. - * cafile?: scalar|null, // A certificate authority file. - * capath?: scalar|null, // A directory that contains multiple certificate authority files. - * local_cert?: scalar|null, // A PEM formatted certificate file. - * local_pk?: scalar|null, // A private key file. - * passphrase?: scalar|null, // The passphrase used to encrypt the "local_pk" file. - * ciphers?: scalar|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...) + * 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|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. + * 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|null, // Rate limiter name to use for throttling requests. // Default: null + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null * caching?: bool|array{ // Caching configuration. - * enabled?: bool, // Default: false - * cache_pool?: string, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" - * shared?: bool, // Indicates whether the cache is shared (public) or private. // Default: true - * max_ttl?: int, // The maximum TTL (in seconds) allowed for cached responses. Null means no cap. // Default: null + * 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, // Default: false - * retry_strategy?: scalar|null, // service id to override the retry strategy. // Default: null + * enabled?: bool|Param, // Default: false + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null * http_codes?: array, + * code?: int|Param, + * methods?: list, * }>, - * max_retries?: int, // Default: 3 - * delay?: int, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 - * multiplier?: float, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 - * max_delay?: int, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 - * jitter?: float, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 + * 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 * }, * }, - * mock_response_factory?: scalar|null, // The id of the service that should generate mock responses. It should be either an invokable or an iterable. + * 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, + * 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, // The maximum number of redirects to follow. - * http_version?: scalar|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. - * resolve?: array, - * proxy?: scalar|null, // The URL of the proxy to pass requests through or null for automatic detection. - * no_proxy?: scalar|null, // A comma separated list of hosts that do not require a proxy to be reached. - * timeout?: float, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. - * max_duration?: float, // The maximum execution time for the request+response as a whole. - * bindto?: scalar|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. - * verify_peer?: bool, // Indicates if the peer should be verified in a TLS context. - * verify_host?: bool, // Indicates if the host should exist as a certificate common name. - * cafile?: scalar|null, // A certificate authority file. - * capath?: scalar|null, // A directory that contains multiple certificate authority files. - * local_cert?: scalar|null, // A PEM formatted certificate file. - * local_pk?: scalar|null, // A private key file. - * passphrase?: scalar|null, // The passphrase used to encrypt the "local_pk" file. - * ciphers?: scalar|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...). + * 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|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. + * 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|null, // Rate limiter name to use for throttling requests. // Default: null + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null * caching?: bool|array{ // Caching configuration. - * enabled?: bool, // Default: false - * cache_pool?: string, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" - * shared?: bool, // Indicates whether the cache is shared (public) or private. // Default: true - * max_ttl?: int, // The maximum TTL (in seconds) allowed for cached responses. Null means no cap. // Default: null + * 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, // Default: false - * retry_strategy?: scalar|null, // service id to override the retry strategy. // Default: null + * enabled?: bool|Param, // Default: false + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null * http_codes?: array, + * code?: int|Param, + * methods?: list, * }>, - * max_retries?: int, // Default: 3 - * delay?: int, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 - * multiplier?: float, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 - * max_delay?: int, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 - * jitter?: float, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 + * 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, // Default: true - * message_bus?: scalar|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null - * dsn?: scalar|null, // Default: null - * transports?: array, + * enabled?: bool|Param, // Default: true + * message_bus?: scalar|Param|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null + * dsn?: scalar|Param|null, // Default: null + * transports?: array, * envelope?: array{ // Mailer Envelope configuration - * sender?: scalar|null, - * recipients?: list, - * allowed_recipients?: list, + * sender?: scalar|Param|null, + * recipients?: list, + * allowed_recipients?: list, * }, * headers?: array, * dkim_signer?: bool|array{ // DKIM signer configuration - * enabled?: bool, // Default: false - * key?: scalar|null, // Key content, or path to key (in PEM format with the `file://` prefix) // Default: "" - * domain?: scalar|null, // Default: "" - * select?: scalar|null, // Default: "" - * passphrase?: scalar|null, // The private key passphrase // Default: "" + * enabled?: bool|Param, // Default: false + * key?: scalar|Param|null, // Key content, or path to key (in PEM format with the `file://` prefix) // Default: "" + * domain?: scalar|Param|null, // Default: "" + * select?: scalar|Param|null, // Default: "" + * passphrase?: scalar|Param|null, // The private key passphrase // Default: "" * options?: array, * }, * smime_signer?: bool|array{ // S/MIME signer configuration - * enabled?: bool, // Default: false - * key?: scalar|null, // Path to key (in PEM format) // Default: "" - * certificate?: scalar|null, // Path to certificate (in PEM format without the `file://` prefix) // Default: "" - * passphrase?: scalar|null, // The private key passphrase // Default: null - * extra_certificates?: scalar|null, // Default: null - * sign_options?: int, // Default: null + * enabled?: bool|Param, // Default: false + * key?: scalar|Param|null, // Path to key (in PEM format) // Default: "" + * certificate?: scalar|Param|null, // Path to certificate (in PEM format without the `file://` prefix) // Default: "" + * passphrase?: scalar|Param|null, // The private key passphrase // Default: null + * extra_certificates?: scalar|Param|null, // Default: null + * sign_options?: int|Param, // Default: null * }, * smime_encrypter?: bool|array{ // S/MIME encrypter configuration - * enabled?: bool, // Default: false - * repository?: scalar|null, // S/MIME certificate repository service. This service shall implement the `Symfony\Component\Mailer\EventListener\SmimeCertificateRepositoryInterface`. // Default: "" - * cipher?: int, // A set of algorithms used to encrypt the message // Default: null + * enabled?: bool|Param, // Default: false + * repository?: scalar|Param|null, // S/MIME certificate repository service. This service shall implement the `Symfony\Component\Mailer\EventListener\SmimeCertificateRepositoryInterface`. // Default: "" + * cipher?: int|Param, // A set of algorithms used to encrypt the message // Default: null * }, * }, * secrets?: bool|array{ - * enabled?: bool, // Default: true - * vault_directory?: scalar|null, // Default: "%kernel.project_dir%/config/secrets/%kernel.runtime_environment%" - * local_dotenv_file?: scalar|null, // Default: "%kernel.project_dir%/.env.%kernel.runtime_environment%.local" - * decryption_env_var?: scalar|null, // Default: "base64:default::SYMFONY_DECRYPTION_SECRET" + * enabled?: bool|Param, // Default: true + * vault_directory?: scalar|Param|null, // Default: "%kernel.project_dir%/config/secrets/%kernel.runtime_environment%" + * local_dotenv_file?: scalar|Param|null, // Default: "%kernel.project_dir%/.env.%kernel.environment%.local" + * decryption_env_var?: scalar|Param|null, // Default: "base64:default::SYMFONY_DECRYPTION_SECRET" * }, * notifier?: bool|array{ // Notifier configuration - * enabled?: bool, // Default: true - * message_bus?: scalar|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null - * chatter_transports?: array, - * texter_transports?: array, - * notification_on_failed_messages?: bool, // Default: false - * channel_policy?: array>, + * enabled?: bool|Param, // Default: true + * message_bus?: scalar|Param|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null + * chatter_transports?: array, + * texter_transports?: array, + * notification_on_failed_messages?: bool|Param, // Default: false + * channel_policy?: array>, * admin_recipients?: list, * }, * rate_limiter?: bool|array{ // Rate limiter configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * limiters?: array, - * limit?: int, // The maximum allowed hits in a fixed interval or burst. - * interval?: scalar|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). + * 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?: 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|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, // Amount of tokens to add each interval. // Default: 1 + * 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, // Default: false - * default_uuid_version?: 7|6|4|1, // Default: 7 - * name_based_uuid_version?: 5|3, // Default: 5 - * name_based_uuid_namespace?: scalar|null, - * time_based_uuid_version?: 7|6|1, // Default: 7 - * time_based_uuid_node?: scalar|null, + * enabled?: bool|Param, // Default: true + * default_uuid_version?: 7|6|4|1|Param, // Default: 7 + * name_based_uuid_version?: 5|3|Param, // Default: 5 + * name_based_uuid_namespace?: scalar|Param|null, + * time_based_uuid_version?: 7|6|1|Param, // Default: 7 + * time_based_uuid_node?: scalar|Param|null, * }, * html_sanitizer?: bool|array{ // HtmlSanitizer configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * sanitizers?: array, - * block_elements?: list, - * drop_elements?: list, + * block_elements?: list, + * drop_elements?: list, * allow_attributes?: array, * drop_attributes?: array, - * force_attributes?: array>, - * force_https_urls?: bool, // Transforms URLs using the HTTP scheme to use the HTTPS scheme instead. // Default: false - * allowed_link_schemes?: list, - * allowed_link_hosts?: list|null, - * allow_relative_links?: bool, // Allows relative URLs to be used in links href attributes. // Default: false - * allowed_media_schemes?: list, - * allowed_media_hosts?: list|null, - * allow_relative_medias?: bool, // Allows relative URLs to be used in media source attributes (img, audio, video, ...). // Default: false - * with_attribute_sanitizers?: list, - * without_attribute_sanitizers?: list, - * max_input_length?: int, // The maximum length allowed for the sanitized input. // Default: 0 + * 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?: list, + * allowed_link_hosts?: list|null, + * allow_relative_links?: bool|Param, // Allows relative URLs to be used in links href attributes. // Default: false + * allowed_media_schemes?: list, + * allowed_media_hosts?: list|null, + * allow_relative_medias?: bool|Param, // Allows relative URLs to be used in media source attributes (img, audio, video, ...). // Default: false + * with_attribute_sanitizers?: list, + * without_attribute_sanitizers?: list, + * max_input_length?: int|Param, // The maximum length allowed for the sanitized input. // Default: 0 * }>, * }, * webhook?: bool|array{ // Webhook configuration - * enabled?: bool, // Default: false - * message_bus?: scalar|null, // The message bus to use. // Default: "messenger.default_bus" + * enabled?: bool|Param, // Default: false + * message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus" * routing?: array, * }, * remote-event?: bool|array{ // RemoteEvent configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * json_streamer?: bool|array{ // JSON streamer configuration - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * } * @psalm-type DoctrineConfig = array{ * dbal?: array{ - * default_connection?: scalar|null, + * default_connection?: scalar|Param|null, * types?: array, - * driver_schemes?: array, + * driver_schemes?: array, * connections?: array, - * mapping_types?: array, - * default_table_options?: array, - * schema_manager_factory?: scalar|null, // Default: "doctrine.dbal.default_schema_manager_factory" - * result_cache?: scalar|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, * replicas?: array, * }>, * }, * orm?: array{ - * default_entity_manager?: scalar|null, - * auto_generate_proxy_classes?: scalar|null, // Auto generate mode possible values are: "NEVER", "ALWAYS", "FILE_NOT_EXISTS", "EVAL", "FILE_NOT_EXISTS_OR_CHANGED", this option is ignored when the "enable_native_lazy_objects" option is true // Default: false - * enable_lazy_ghost_objects?: bool, // Enables the new implementation of proxies based on lazy ghosts instead of using the legacy implementation // Default: true - * enable_native_lazy_objects?: bool, // Enables the new native implementation of PHP lazy objects instead of generated proxies // Default: false - * proxy_dir?: scalar|null, // Configures the path where generated proxy classes are saved when using non-native lazy objects, this option is ignored when the "enable_native_lazy_objects" option is true // Default: "%kernel.build_dir%/doctrine/orm/Proxies" - * proxy_namespace?: scalar|null, // Defines the root namespace for generated proxy classes when using non-native lazy objects, this option is ignored when the "enable_native_lazy_objects" option is true // Default: "Proxies" + * default_entity_manager?: scalar|Param|null, + * enable_native_lazy_objects?: bool|Param, // Deprecated: The "enable_native_lazy_objects" option is deprecated and will be removed in DoctrineBundle 4.0, as native lazy objects are now always enabled. // Default: true * controller_resolver?: bool|array{ - * enabled?: bool, // Default: true - * auto_mapping?: bool|null, // Set to false to disable using route placeholders as lookup criteria when the primary key doesn't match the argument name // Default: null - * evict_cache?: bool, // Set to true to fetch the entity from the database instead of using the cache, if any // Default: false + * enabled?: bool|Param, // Default: true + * auto_mapping?: bool|Param, // Deprecated: The "doctrine.orm.controller_resolver.auto_mapping.auto_mapping" option is deprecated and will be removed in DoctrineBundle 4.0, as it only accepts `false` since 3.0. // Set to true to enable using route placeholders as lookup criteria when the primary key doesn't match the argument name // Default: false + * 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, * }>, * }>, * }, - * connection?: scalar|null, - * class_metadata_factory_name?: scalar|null, // Default: "Doctrine\\ORM\\Mapping\\ClassMetadataFactory" - * default_repository_class?: scalar|null, // Default: "Doctrine\\ORM\\EntityRepository" - * auto_mapping?: scalar|null, // Default: false - * naming_strategy?: scalar|null, // Default: "doctrine.orm.naming_strategy.default" - * quote_strategy?: scalar|null, // Default: "doctrine.orm.quote_strategy.default" - * typed_field_mapper?: scalar|null, // Default: "doctrine.orm.typed_field_mapper.default" - * entity_listener_resolver?: scalar|null, // Default: null - * fetch_mode_subselect_batch_size?: scalar|null, - * repository_factory?: scalar|null, // Default: "doctrine.orm.container_repository_factory" - * schema_ignore_classes?: list, - * report_fields_where_declared?: bool, // 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, // 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 + * 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, + * 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 and will be mandatory in ORM 3.0. See https://github.com/doctrine/orm/pull/6728. // Default: false * second_level_cache?: array{ * region_cache_driver?: string|array{ - * type?: scalar|null, // Default: null - * id?: scalar|null, - * pool?: scalar|null, + * type?: scalar|Param|null, // Default: null + * id?: scalar|Param|null, + * pool?: scalar|Param|null, * }, - * region_lock_lifetime?: scalar|null, // Default: 60 - * log_enabled?: bool, // Default: true - * region_lifetime?: scalar|null, // Default: 3600 - * enabled?: bool, // Default: true - * factory?: scalar|null, + * 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, + * hydrators?: array, * mappings?: array, * dql?: array{ - * string_functions?: array, - * numeric_functions?: array, - * datetime_functions?: array, + * string_functions?: array, + * numeric_functions?: array, + * datetime_functions?: array, * }, * filters?: array, * }>, - * identity_generation_preferences?: array, + * identity_generation_preferences?: array, * }>, - * resolve_target_entities?: array, + * resolve_target_entities?: array, * }, * } * @psalm-type DoctrineMigrationsConfig = array{ - * enable_service_migrations?: bool, // Whether to enable fetching migrations from the service container. // Default: false - * migrations_paths?: array, - * services?: array, - * factories?: array, + * enable_service_migrations?: bool|Param, // Whether to enable fetching migrations from the service container. // Default: false + * migrations_paths?: array, + * services?: array, + * factories?: array, * storage?: array{ // Storage to use for migration status metadata. * table_storage?: array{ // The default metadata storage, implemented as a table in the database. - * table_name?: scalar|null, // Default: null - * version_column_name?: scalar|null, // Default: null - * version_column_length?: scalar|null, // Default: null - * executed_at_column_name?: scalar|null, // Default: null - * execution_time_column_name?: scalar|null, // Default: null + * table_name?: scalar|Param|null, // Default: null + * version_column_name?: scalar|Param|null, // Default: null + * version_column_length?: scalar|Param|null, // Default: null + * executed_at_column_name?: scalar|Param|null, // Default: null + * execution_time_column_name?: scalar|Param|null, // Default: null * }, * }, - * migrations?: list, - * connection?: scalar|null, // Connection name to use for the migrations database. // Default: null - * em?: scalar|null, // Entity manager name to use for the migrations database (available when doctrine/orm is installed). // Default: null - * all_or_nothing?: scalar|null, // Run all migrations in a transaction. // Default: false - * check_database_platform?: scalar|null, // Adds an extra check in the generated migrations to allow execution only on the same platform as they were initially generated on. // Default: true - * custom_template?: scalar|null, // Custom template path for generated migration classes. // Default: null - * organize_migrations?: scalar|null, // Organize migrations mode. Possible values are: "BY_YEAR", "BY_YEAR_AND_MONTH", false // Default: false - * enable_profiler?: bool, // Whether or not to enable the profiler collector to calculate and visualize migration status. This adds some queries overhead. // Default: false - * transactional?: bool, // Whether or not to wrap migrations in a single transaction. // Default: true + * migrations?: list, + * connection?: scalar|Param|null, // Connection name to use for the migrations database. // Default: null + * em?: scalar|Param|null, // Entity manager name to use for the migrations database (available when doctrine/orm is installed). // Default: null + * all_or_nothing?: scalar|Param|null, // Run all migrations in a transaction. // Default: false + * check_database_platform?: scalar|Param|null, // Adds an extra check in the generated migrations to allow execution only on the same platform as they were initially generated on. // Default: true + * custom_template?: scalar|Param|null, // Custom template path for generated migration classes. // Default: null + * organize_migrations?: scalar|Param|null, // Organize migrations mode. Possible values are: "BY_YEAR", "BY_YEAR_AND_MONTH", false // Default: false + * enable_profiler?: bool|Param, // Whether or not to enable the profiler collector to calculate and visualize migration status. This adds some queries overhead. // Default: false + * transactional?: bool|Param, // Whether or not to wrap migrations in a single transaction. // Default: true * } * @psalm-type DebugConfig = array{ - * max_items?: int, // Max number of displayed items past the first level, -1 means no limit. // Default: 2500 - * min_depth?: int, // Minimum tree depth to clone all the items, 1 is default. // Default: 1 - * max_string_length?: int, // Max length of displayed strings, -1 means no limit. // Default: -1 - * dump_destination?: scalar|null, // A stream URL where dumps should be written to. // Default: null - * theme?: "dark"|"light", // Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light". // Default: "dark" + * max_items?: int|Param, // Max number of displayed items past the first level, -1 means no limit. // Default: 2500 + * min_depth?: int|Param, // Minimum tree depth to clone all the items, 1 is default. // Default: 1 + * max_string_length?: int|Param, // Max length of displayed strings, -1 means no limit. // Default: -1 + * dump_destination?: scalar|Param|null, // A stream URL where dumps should be written to. // Default: null + * theme?: "dark"|"light"|Param, // Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light". // Default: "dark" * } * @psalm-type TwigConfig = array{ - * form_themes?: list, + * form_themes?: list, * globals?: array, - * autoescape_service?: scalar|null, // Default: null - * autoescape_service_method?: scalar|null, // Default: null - * base_template_class?: scalar|null, // Deprecated: The child node "base_template_class" at path "twig.base_template_class" is deprecated. - * cache?: scalar|null, // Default: true - * charset?: scalar|null, // Default: "%kernel.charset%" - * debug?: bool, // Default: "%kernel.debug%" - * strict_variables?: bool, // Default: "%kernel.debug%" - * auto_reload?: scalar|null, - * optimizations?: int, - * default_path?: scalar|null, // The default path used to load templates. // Default: "%kernel.project_dir%/templates" - * file_name_pattern?: list, + * autoescape_service?: scalar|Param|null, // Default: null + * autoescape_service_method?: scalar|Param|null, // Default: null + * cache?: scalar|Param|null, // Default: true + * charset?: scalar|Param|null, // Default: "%kernel.charset%" + * debug?: bool|Param, // Default: "%kernel.debug%" + * strict_variables?: bool|Param, // Default: "%kernel.debug%" + * auto_reload?: scalar|Param|null, + * optimizations?: int|Param, + * default_path?: scalar|Param|null, // The default path used to load templates. // Default: "%kernel.project_dir%/templates" + * file_name_pattern?: list, * paths?: array, * date?: array{ // The default format options used by the date filter. - * format?: scalar|null, // Default: "F j, Y H:i" - * interval_format?: scalar|null, // Default: "%d days" - * timezone?: scalar|null, // The timezone used when formatting dates, when set to null, the timezone returned by date_default_timezone_get() is used. // Default: null + * format?: scalar|Param|null, // Default: "F j, Y H:i" + * interval_format?: scalar|Param|null, // Default: "%d days" + * timezone?: scalar|Param|null, // The timezone used when formatting dates, when set to null, the timezone returned by date_default_timezone_get() is used. // Default: null * }, * number_format?: array{ // The default format options for the number_format filter. - * decimals?: int, // Default: 0 - * decimal_point?: scalar|null, // Default: "." - * thousands_separator?: scalar|null, // Default: "," + * decimals?: int|Param, // Default: 0 + * decimal_point?: scalar|Param|null, // Default: "." + * thousands_separator?: scalar|Param|null, // Default: "," * }, * mailer?: array{ - * html_to_text_converter?: scalar|null, // A service implementing the "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface". // Default: null + * html_to_text_converter?: scalar|Param|null, // A service implementing the "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface". // Default: null * }, * } * @psalm-type WebProfilerConfig = array{ * toolbar?: bool|array{ // Profiler toolbar configuration - * enabled?: bool, // Default: false - * ajax_replace?: bool, // Replace toolbar on AJAX requests // Default: false + * enabled?: bool|Param, // Default: false + * ajax_replace?: bool|Param, // Replace toolbar on AJAX requests // Default: false * }, - * intercept_redirects?: bool, // Default: false - * excluded_ajax_paths?: scalar|null, // Default: "^/((index|app(_[\\w]+)?)\\.php/)?_wdt" - * } - * @psalm-type StimulusConfig = array{ - * controller_paths?: list, - * controllers_json?: scalar|null, // Default: "%kernel.project_dir%/assets/controllers.json" - * } - * @psalm-type TurboConfig = array{ - * broadcast?: bool|array{ - * enabled?: bool, // Default: true - * entity_template_prefixes?: list, - * doctrine_orm?: bool|array{ // Enable the Doctrine ORM integration - * enabled?: bool, // Default: true - * }, - * }, - * default_transport?: scalar|null, // Default: "default" + * intercept_redirects?: bool|Param, // Default: false + * excluded_ajax_paths?: scalar|Param|null, // Default: "^/((index|app(_[\\w]+)?)\\.php/)?_wdt" * } * @psalm-type TwigExtraConfig = array{ * cache?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * html?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * markdown?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * intl?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: true * }, * cssinliner?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * inky?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * string?: bool|array{ - * enabled?: bool, // Default: false + * enabled?: bool|Param, // Default: false * }, * commonmark?: array{ * renderer?: array{ // Array of options for rendering HTML. - * block_separator?: scalar|null, - * inner_separator?: scalar|null, - * soft_break?: scalar|null, + * block_separator?: scalar|Param|null, + * inner_separator?: scalar|Param|null, + * soft_break?: scalar|Param|null, * }, - * html_input?: "strip"|"allow"|"escape", // How to handle HTML input. - * allow_unsafe_links?: bool, // Remove risky link and image URLs by setting this to false. // Default: true - * max_nesting_level?: int, // The maximum nesting level for blocks. // Default: 9223372036854775807 - * max_delimiters_per_line?: int, // The maximum number of strong/emphasis delimiters per line. // Default: 9223372036854775807 + * html_input?: "strip"|"allow"|"escape"|Param, // How to handle HTML input. + * allow_unsafe_links?: bool|Param, // Remove risky link and image URLs by setting this to false. // Default: true + * max_nesting_level?: int|Param, // The maximum nesting level for blocks. // Default: 9223372036854775807 + * max_delimiters_per_line?: int|Param, // The maximum number of strong/emphasis delimiters per line. // Default: 9223372036854775807 * slug_normalizer?: array{ // Array of options for configuring how URL-safe slugs are created. * instance?: mixed, - * max_length?: int, // Default: 255 + * max_length?: int|Param, // Default: 255 * unique?: mixed, * }, * commonmark?: array{ // Array of options for configuring the CommonMark core extension. - * enable_em?: bool, // Default: true - * enable_strong?: bool, // Default: true - * use_asterisk?: bool, // Default: true - * use_underscore?: bool, // Default: true - * unordered_list_markers?: list, + * enable_em?: bool|Param, // Default: true + * enable_strong?: bool|Param, // Default: true + * use_asterisk?: bool|Param, // Default: true + * use_underscore?: bool|Param, // Default: true + * unordered_list_markers?: list, * }, * ... * }, * } * @psalm-type SecurityConfig = array{ - * access_denied_url?: scalar|null, // Default: null - * session_fixation_strategy?: "none"|"migrate"|"invalidate", // Default: "migrate" - * hide_user_not_found?: bool, // Deprecated: The "hide_user_not_found" option is deprecated and will be removed in 8.0. Use the "expose_security_errors" option instead. - * expose_security_errors?: \Symfony\Component\Security\Http\Authentication\ExposeSecurityLevel::None|\Symfony\Component\Security\Http\Authentication\ExposeSecurityLevel::AccountStatus|\Symfony\Component\Security\Http\Authentication\ExposeSecurityLevel::All, // Default: "none" - * erase_credentials?: bool, // Default: true + * access_denied_url?: scalar|Param|null, // Default: null + * session_fixation_strategy?: "none"|"migrate"|"invalidate"|Param, // Default: "migrate" + * expose_security_errors?: \Symfony\Component\Security\Http\Authentication\ExposeSecurityLevel::None|\Symfony\Component\Security\Http\Authentication\ExposeSecurityLevel::AccountStatus|\Symfony\Component\Security\Http\Authentication\ExposeSecurityLevel::All|Param, // Default: "none" + * erase_credentials?: bool|Param, // Default: true * access_decision_manager?: array{ - * strategy?: "affirmative"|"consensus"|"unanimous"|"priority", - * service?: scalar|null, - * strategy_service?: scalar|null, - * allow_if_all_abstain?: bool, // Default: false - * allow_if_equal_granted_denied?: bool, // Default: true + * strategy?: "affirmative"|"consensus"|"unanimous"|"priority"|Param, + * service?: scalar|Param|null, + * strategy_service?: scalar|Param|null, + * allow_if_all_abstain?: bool|Param, // Default: false + * allow_if_equal_granted_denied?: bool|Param, // Default: true * }, * password_hashers?: array, - * hash_algorithm?: scalar|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|null, // Default: 40 - * ignore_case?: bool, // Default: false - * encode_as_base64?: bool, // Default: true - * iterations?: scalar|null, // Default: 5000 - * cost?: int, // Default: null - * memory_cost?: scalar|null, // Default: null - * time_cost?: scalar|null, // Default: null - * id?: scalar|null, + * algorithm?: scalar|Param|null, + * migrate_from?: 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, + * providers?: list, * }, * entity?: array{ - * class: scalar|null, // The full entity class name of your user class. - * property?: scalar|null, // Default: null - * manager_name?: scalar|null, // Default: null + * 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, + * password?: scalar|Param|null, // Default: null + * roles?: list, * }>, * }, * ldap?: array{ - * service: scalar|null, - * base_dn: scalar|null, - * search_dn?: scalar|null, // Default: null - * search_password?: scalar|null, // Default: null - * extra_fields?: list, - * default_roles?: list, - * role_fetcher?: scalar|null, // Default: null - * uid_key?: scalar|null, // Default: "sAMAccountName" - * filter?: scalar|null, // Default: "({uid_key}={user_identifier})" - * password_attribute?: scalar|null, // Default: null + * 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?: 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 * }, * }>, * firewalls: array, - * security?: bool, // Default: true - * user_checker?: scalar|null, // The UserChecker to use when authenticating users in this firewall. // Default: "security.user_checker" - * request_matcher?: scalar|null, - * access_denied_url?: scalar|null, - * access_denied_handler?: scalar|null, - * entry_point?: scalar|null, // An enabled authenticator name or a service id that implements "Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface". - * provider?: scalar|null, - * stateless?: bool, // Default: false - * lazy?: bool, // Default: false - * context?: scalar|null, + * pattern?: scalar|Param|null, + * host?: scalar|Param|null, + * methods?: 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|null, // Default: null - * csrf_token_id?: scalar|null, // Default: "logout" - * csrf_parameter?: scalar|null, // Default: "_csrf_token" - * csrf_token_manager?: scalar|null, - * path?: scalar|null, // Default: "/logout" - * target?: scalar|null, // Default: "/" - * invalidate_session?: bool, // Default: true - * clear_site_data?: list<"*"|"cache"|"cookies"|"storage"|"executionContexts">, + * 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?: list<"*"|"cache"|"cookies"|"storage"|"executionContexts"|Param>, * delete_cookies?: array, * }, * switch_user?: array{ - * provider?: scalar|null, - * parameter?: scalar|null, // Default: "_switch_user" - * role?: scalar|null, // Default: "ROLE_ALLOWED_TO_SWITCH" - * target_route?: scalar|null, // Default: null + * 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, + * required_badges?: list, + * custom_authenticators?: list, * login_throttling?: array{ - * limiter?: scalar|null, // A service id implementing "Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface". - * max_attempts?: int, // Default: 5 - * interval?: scalar|null, // Default: "1 minute" - * lock_factory?: scalar|null, // The service ID of the lock factory used by the login rate limiter (or null to disable locking). // Default: null - * cache_pool?: string, // The cache pool to use for storing the limiter state // Default: "cache.rate_limiter" - * storage_service?: string, // The service ID of a custom storage implementation, this precedes any configured "cache_pool" // Default: null + * 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 * }, * x509?: array{ - * provider?: scalar|null, - * user?: scalar|null, // Default: "SSL_CLIENT_S_DN_Email" - * credentials?: scalar|null, // Default: "SSL_CLIENT_S_DN" - * user_identifier?: scalar|null, // Default: "emailAddress" + * 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|null, - * user?: scalar|null, // Default: "REMOTE_USER" + * provider?: scalar|Param|null, + * user?: scalar|Param|null, // Default: "REMOTE_USER" * }, * login_link?: array{ - * check_route: scalar|null, // Route that will validate the login link - e.g. "app_login_link_verify". - * check_post_only?: scalar|null, // If true, only HTTP POST requests to "check_route" will be handled by the authenticator. // Default: false - * signature_properties: list, - * lifetime?: int, // The lifetime of the login link in seconds. // Default: 600 - * max_uses?: int, // Max number of times a login link can be used - null means unlimited within lifetime. // Default: null - * used_link_cache?: scalar|null, // Cache service id used to expired links of max_uses is set. - * success_handler?: scalar|null, // A service id that implements Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface. - * failure_handler?: scalar|null, // A service id that implements Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface. - * provider?: scalar|null, // The user provider to load users from. - * secret?: scalar|null, // Default: "%kernel.secret%" - * always_use_default_target_path?: bool, // Default: false - * default_target_path?: scalar|null, // Default: "/" - * login_path?: scalar|null, // Default: "/login" - * target_path_parameter?: scalar|null, // Default: "_target_path" - * use_referer?: bool, // Default: false - * failure_path?: scalar|null, // Default: null - * failure_forward?: bool, // Default: false - * failure_path_parameter?: scalar|null, // Default: "_failure_path" + * 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|null, - * remember_me?: bool, // Default: true - * success_handler?: scalar|null, - * failure_handler?: scalar|null, - * check_path?: scalar|null, // Default: "/login_check" - * use_forward?: bool, // Default: false - * login_path?: scalar|null, // Default: "/login" - * username_parameter?: scalar|null, // Default: "_username" - * password_parameter?: scalar|null, // Default: "_password" - * csrf_parameter?: scalar|null, // Default: "_csrf_token" - * csrf_token_id?: scalar|null, // Default: "authenticate" - * enable_csrf?: bool, // Default: false - * post_only?: bool, // Default: true - * form_only?: bool, // Default: false - * always_use_default_target_path?: bool, // Default: false - * default_target_path?: scalar|null, // Default: "/" - * target_path_parameter?: scalar|null, // Default: "_target_path" - * use_referer?: bool, // Default: false - * failure_path?: scalar|null, // Default: null - * failure_forward?: bool, // Default: false - * failure_path_parameter?: scalar|null, // Default: "_failure_path" + * 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|null, - * remember_me?: bool, // Default: true - * success_handler?: scalar|null, - * failure_handler?: scalar|null, - * check_path?: scalar|null, // Default: "/login_check" - * use_forward?: bool, // Default: false - * login_path?: scalar|null, // Default: "/login" - * username_parameter?: scalar|null, // Default: "_username" - * password_parameter?: scalar|null, // Default: "_password" - * csrf_parameter?: scalar|null, // Default: "_csrf_token" - * csrf_token_id?: scalar|null, // Default: "authenticate" - * enable_csrf?: bool, // Default: false - * post_only?: bool, // Default: true - * form_only?: bool, // Default: false - * always_use_default_target_path?: bool, // Default: false - * default_target_path?: scalar|null, // Default: "/" - * target_path_parameter?: scalar|null, // Default: "_target_path" - * use_referer?: bool, // Default: false - * failure_path?: scalar|null, // Default: null - * failure_forward?: bool, // Default: false - * failure_path_parameter?: scalar|null, // Default: "_failure_path" - * service?: scalar|null, // Default: "ldap" - * dn_string?: scalar|null, // Default: "{user_identifier}" - * query_string?: scalar|null, - * search_dn?: scalar|null, // Default: "" - * search_password?: scalar|null, // Default: "" + * 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|null, - * remember_me?: bool, // Default: true - * success_handler?: scalar|null, - * failure_handler?: scalar|null, - * check_path?: scalar|null, // Default: "/login_check" - * use_forward?: bool, // Default: false - * login_path?: scalar|null, // Default: "/login" - * username_path?: scalar|null, // Default: "username" - * password_path?: scalar|null, // Default: "password" + * 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|null, - * remember_me?: bool, // Default: true - * success_handler?: scalar|null, - * failure_handler?: scalar|null, - * check_path?: scalar|null, // Default: "/login_check" - * use_forward?: bool, // Default: false - * login_path?: scalar|null, // Default: "/login" - * username_path?: scalar|null, // Default: "username" - * password_path?: scalar|null, // Default: "password" - * service?: scalar|null, // Default: "ldap" - * dn_string?: scalar|null, // Default: "{user_identifier}" - * query_string?: scalar|null, - * search_dn?: scalar|null, // Default: "" - * search_password?: scalar|null, // Default: "" + * 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|null, - * remember_me?: bool, // Default: true - * success_handler?: scalar|null, - * failure_handler?: scalar|null, - * realm?: scalar|null, // Default: null - * token_extractors?: list, + * 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?: list, * token_handler: string|array{ - * id?: scalar|null, + * id?: scalar|Param|null, * oidc_user_info?: string|array{ - * base_uri: scalar|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). + * 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|null, // Cache service id to use to cache the OIDC discovery configuration. + * id: scalar|Param|null, // Cache service id to use to cache the OIDC discovery configuration. * }, * }, - * claim?: scalar|null, // Claim which contains the user identifier (e.g. sub, email, etc.). // Default: "sub" - * client?: scalar|null, // HttpClient service id to use to call the OIDC server. + * 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: list, + * base_uri: list, * cache?: array{ - * id: scalar|null, // Cache service id to use to cache the OIDC discovery configuration. + * id: scalar|Param|null, // Cache service id to use to cache the OIDC discovery configuration. * }, * }, - * claim?: scalar|null, // Claim which contains the user identifier (e.g.: sub, email..). // Default: "sub" - * audience: scalar|null, // Audience set in the token, for validation purpose. - * issuers: list, - * algorithm?: array, - * algorithms: list, - * key?: scalar|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|null, // JSON-encoded JWKSet used to sign the token (must contain a list of valid public keys). + * 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, + * algorithms: list, + * 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, // Default: false - * enforce?: bool, // When enabled, the token shall be encrypted. // Default: false - * algorithms: list, - * keyset: scalar|null, // JSON-encoded JWKSet used to decrypt the token (must contain a list of valid private keys). + * 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|null, // CAS server validation URL - * prefix?: scalar|null, // CAS prefix // Default: "cas" - * http_client?: scalar|null, // HTTP Client service // Default: null + * 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|null, + * oauth2?: scalar|Param|null, * }, * }, * http_basic?: array{ - * provider?: scalar|null, - * realm?: scalar|null, // Default: "Secured Area" + * provider?: scalar|Param|null, + * realm?: scalar|Param|null, // Default: "Secured Area" * }, * http_basic_ldap?: array{ - * provider?: scalar|null, - * realm?: scalar|null, // Default: "Secured Area" - * service?: scalar|null, // Default: "ldap" - * dn_string?: scalar|null, // Default: "{user_identifier}" - * query_string?: scalar|null, - * search_dn?: scalar|null, // Default: "" - * search_password?: scalar|null, // Default: "" + * 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|null, // Default: "%kernel.secret%" - * service?: scalar|null, - * user_providers?: list, - * catch_exceptions?: bool, // Default: true - * signature_properties?: list, + * secret?: scalar|Param|null, // Default: "%kernel.secret%" + * service?: scalar|Param|null, + * user_providers?: list, + * catch_exceptions?: bool|Param, // Default: true + * signature_properties?: list, * token_provider?: string|array{ - * service?: scalar|null, // The service ID of a custom remember-me token provider. + * service?: scalar|Param|null, // The service ID of a custom remember-me token provider. * doctrine?: bool|array{ - * enabled?: bool, // Default: false - * connection?: scalar|null, // Default: null + * enabled?: bool|Param, // Default: false + * connection?: scalar|Param|null, // Default: null * }, * }, - * token_verifier?: scalar|null, // The service ID of a custom rememberme token verifier. - * name?: scalar|null, // Default: "REMEMBERME" - * lifetime?: int, // Default: 31536000 - * path?: scalar|null, // Default: "/" - * domain?: scalar|null, // Default: null - * secure?: true|false|"auto", // Default: false - * httponly?: bool, // Default: true - * samesite?: null|"lax"|"strict"|"none", // Default: null - * always_remember_me?: bool, // Default: false - * remember_me_parameter?: scalar|null, // Default: "_remember_me" + * 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: true + * httponly?: bool|Param, // Default: true + * samesite?: null|"lax"|"strict"|"none"|Param, // Default: null + * always_remember_me?: bool|Param, // Default: false + * remember_me_parameter?: scalar|Param|null, // Default: "_remember_me" + * }, + * 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 * }, * }>, * access_control?: list, - * attributes?: array, - * route?: scalar|null, // Default: null - * methods?: list, - * allow_if?: scalar|null, // Default: null - * roles?: 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?: list, + * attributes?: array, + * route?: scalar|Param|null, // Default: null + * methods?: list, + * allow_if?: scalar|Param|null, // Default: null + * roles?: list, * }>, - * role_hierarchy?: array>, + * role_hierarchy?: array>, * } * @psalm-type MonologConfig = array{ - * use_microseconds?: scalar|null, // Default: true - * channels?: list, + * use_microseconds?: scalar|Param|null, // Default: true + * channels?: list, * handlers?: array, + * code?: scalar|Param|null, + * urls?: list, * }>, - * accepted_levels?: list, - * min_level?: scalar|null, // Default: "DEBUG" - * max_level?: scalar|null, // Default: "EMERGENCY" - * buffer_size?: scalar|null, // Default: 0 - * flush_on_overflow?: bool, // Default: false - * handler?: scalar|null, - * url?: scalar|null, - * exchange?: scalar|null, - * exchange_name?: scalar|null, // Default: "log" - * channel?: scalar|null, // Default: null - * bot_name?: scalar|null, // Default: "Monolog" - * use_attachment?: scalar|null, // Default: true - * use_short_attachment?: scalar|null, // Default: false - * include_extra?: scalar|null, // Default: false - * icon_emoji?: scalar|null, // Default: null - * webhook_url?: scalar|null, - * exclude_fields?: list, - * token?: scalar|null, - * region?: scalar|null, - * source?: scalar|null, - * use_ssl?: bool, // Default: true + * 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|null, // Default: null - * host?: scalar|null, // Default: null - * port?: scalar|null, // Default: 514 - * config?: list, - * members?: list, - * connection_string?: scalar|null, - * timeout?: scalar|null, - * time?: scalar|null, // Default: 60 - * deduplication_level?: scalar|null, // Default: 400 - * store?: scalar|null, // Default: null - * connection_timeout?: scalar|null, - * persistent?: bool, - * message_type?: scalar|null, // Default: 0 - * parse_mode?: scalar|null, // Default: null - * disable_webpage_preview?: bool|null, // Default: null - * disable_notification?: bool|null, // Default: null - * split_long_messages?: bool, // Default: false - * delay_between_messages?: bool, // Default: false - * topic?: int, // Default: null - * factor?: int, // Default: 1 - * tags?: list, + * 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?: list, * console_formatter_options?: mixed, // Default: [] - * formatter?: scalar|null, - * nested?: bool, // Default: false + * formatter?: scalar|Param|null, + * nested?: bool|Param, // Default: false * publisher?: string|array{ - * id?: scalar|null, - * hostname?: scalar|null, - * port?: scalar|null, // Default: 12201 - * chunk_size?: scalar|null, // Default: 1420 - * encoder?: "json"|"compressed_json", + * 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|null, // ID of a MongoDB\Client service - * uri?: scalar|null, - * username?: scalar|null, - * password?: scalar|null, - * database?: scalar|null, // Default: "monolog" - * collection?: scalar|null, // Default: "logs" + * 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|null, - * hosts?: list, - * host?: scalar|null, - * port?: scalar|null, // Default: 9200 - * transport?: scalar|null, // Default: "Http" - * user?: scalar|null, // Default: null - * password?: scalar|null, // Default: null + * 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|null, // Default: "monolog" - * document_type?: scalar|null, // Default: "logs" - * ignore_error?: scalar|null, // Default: false + * 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|null, - * host?: scalar|null, - * password?: scalar|null, // Default: null - * port?: scalar|null, // Default: 6379 - * database?: scalar|null, // Default: 0 - * key_name?: scalar|null, // Default: "monolog_redis" + * 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|null, - * host?: scalar|null, + * id?: scalar|Param|null, + * host?: scalar|Param|null, * }, - * from_email?: scalar|null, - * to_email?: list, - * subject?: scalar|null, - * content_type?: scalar|null, // Default: null - * headers?: list, - * mailer?: scalar|null, // Default: null + * from_email?: scalar|Param|null, + * to_email?: 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|null, - * method?: scalar|null, // Default: null + * id: scalar|Param|null, + * method?: scalar|Param|null, // Default: null * }, * verbosity_levels?: array{ - * VERBOSITY_QUIET?: scalar|null, // Default: "ERROR" - * VERBOSITY_NORMAL?: scalar|null, // Default: "WARNING" - * VERBOSITY_VERBOSE?: scalar|null, // Default: "NOTICE" - * VERBOSITY_VERY_VERBOSE?: scalar|null, // Default: "INFO" - * VERBOSITY_DEBUG?: scalar|null, // Default: "DEBUG" + * 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|null, - * elements?: list, + * type?: scalar|Param|null, + * elements?: list, * }, * }>, * } * @psalm-type MakerConfig = array{ - * root_namespace?: scalar|null, // Default: "App" - * generate_final_classes?: bool, // Default: true - * generate_final_entities?: bool, // Default: false + * root_namespace?: scalar|Param|null, // Default: "App" + * generate_final_classes?: bool|Param, // Default: true + * generate_final_entities?: bool|Param, // Default: false + * } + * @psalm-type KnpPaginatorConfig = array{ + * default_options?: array{ + * sort_field_name?: scalar|Param|null, // Default: "sort" + * sort_direction_name?: scalar|Param|null, // Default: "direction" + * filter_field_name?: scalar|Param|null, // Default: "filterField" + * filter_value_name?: scalar|Param|null, // Default: "filterValue" + * page_name?: scalar|Param|null, // Default: "page" + * distinct?: bool|Param, // Default: true + * page_out_of_range?: scalar|Param|null, // Default: "ignore" + * default_limit?: scalar|Param|null, // Default: 10 + * }, + * template?: array{ + * pagination?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/sliding.html.twig" + * rel_links?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/rel_links.html.twig" + * filtration?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/filtration.html.twig" + * sortable?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/sortable_link.html.twig" + * }, + * page_range?: scalar|Param|null, // Default: 5 + * page_limit?: scalar|Param|null, // Default: null + * convert_exception?: bool|Param, // Default: false + * remove_first_page_param?: bool|Param, // Default: false + * } + * @psalm-type FlysystemConfig = array{ + * storages?: array, + * visibility?: scalar|Param|null, // Default: null + * directory_visibility?: scalar|Param|null, // Default: null + * retain_visibility?: bool|Param|null, // Default: null + * case_sensitive?: bool|Param, // Default: true + * disable_asserts?: bool|Param, // Default: false + * public_url?: list, + * path_normalizer?: scalar|Param|null, // Default: null + * public_url_generator?: scalar|Param|null, // Default: null + * temporary_url_generator?: scalar|Param|null, // Default: null + * read_only?: bool|Param, // Default: false + * }>, + * } + * @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" + * }, + * }>, + * 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, + * }, + * }, + * 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: "" + * data_loader?: scalar|Param|null, // Default: "default" + * default_image?: scalar|Param|null, // Default: null + * default_filter_set_settings?: array{ + * quality?: scalar|Param|null, // Default: 100 + * jpeg_quality?: scalar|Param|null, // Default: null + * png_compression_level?: scalar|Param|null, // Default: null + * png_compression_filter?: scalar|Param|null, // Default: null + * format?: scalar|Param|null, // Default: null + * animated?: bool|Param, // Default: false + * cache?: scalar|Param|null, // Default: null + * data_loader?: scalar|Param|null, // Default: null + * default_image?: scalar|Param|null, // Default: null + * filters?: array>, + * post_processors?: array>, + * }, + * controller?: array{ + * filter_action?: scalar|Param|null, // Default: "Liip\\ImagineBundle\\Controller\\ImagineController::filterAction" + * filter_runtime_action?: scalar|Param|null, // Default: "Liip\\ImagineBundle\\Controller\\ImagineController::filterRuntimeAction" + * redirect_response_code?: int|Param, // Default: 302 + * }, + * filter_sets?: 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 + * }, + * enqueue?: bool|Param, // Enables integration with enqueue if set true. Allows resolve image caches in background by sending messages to MQ. // Default: false + * messenger?: bool|array{ // Enables integration with symfony/messenger if set true. Warmup image caches in background by sending messages to MQ. + * enabled?: bool|Param, // Default: false + * }, + * templating?: bool|Param, // Enables integration with symfony/templating component // Default: true + * webp?: array{ + * generate?: bool|Param, // Default: false + * quality?: int|Param, // Default: 100 + * cache?: scalar|Param|null, // Default: null + * data_loader?: scalar|Param|null, // Default: null + * post_processors?: array>, + * }, + * } + * @psalm-type NelmioCorsConfig = array{ + * defaults?: array{ + * allow_credentials?: bool|Param, // Default: false + * allow_origin?: list, + * allow_headers?: list, + * allow_methods?: list, + * allow_private_network?: bool|Param, // Default: false + * expose_headers?: list, + * max_age?: scalar|Param|null, // Default: 0 + * hosts?: list, + * origin_regex?: bool|Param, // Default: false + * forced_allow_origin_value?: scalar|Param|null, // Default: null + * 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, + * }>, + * } + * @psalm-type PrestaSitemapConfig = array{ + * generator?: scalar|Param|null, // Default: "presta_sitemap.generator_default" + * dumper?: scalar|Param|null, // Default: "presta_sitemap.dumper_default" + * timetolive?: int|Param, // Default: 3600 + * sitemap_file_prefix?: scalar|Param|null, // Sets sitemap filename prefix defaults to "sitemap" -> sitemap.xml (for index); sitemap.
.xml(.gz) (for sitemaps) // Default: "sitemap" + * items_by_set?: int|Param, // The maximum number of items allowed in single sitemap. // Default: 50000 + * route_annotation_listener?: scalar|Param|null, // Default: true + * dump_directory?: scalar|Param|null, // The directory to which the sitemap will be dumped. It can be either absolute, or relative (to the place where the command will be triggered). Default to Symfony's public dir. // Default: "%kernel.project_dir%/public" + * defaults?: array{ + * priority?: scalar|Param|null, // Default: 0.5 + * changefreq?: scalar|Param|null, // Default: "daily" + * lastmod?: scalar|Param|null, // Default: "now" + * }, + * default_section?: scalar|Param|null, // The default section in which static routes are registered. // Default: "default" + * alternate?: bool|array{ // Automatically generate alternate (hreflang) urls with static routes. Requires route_annotation_listener config to be enabled. + * enabled?: bool|Param, // Default: false + * default_locale?: scalar|Param|null, // The default locale of your routes. // Default: "en" + * locales?: list, + * i18n?: "symfony"|"jms"|Param, // Strategy used to create your i18n routes. // Default: "symfony" + * }, + * } + * @psalm-type SentryConfig = array{ + * dsn?: scalar|Param|null, // If this value is not provided, the SDK will try to read it from the SENTRY_DSN environment variable. If that variable also does not exist, the SDK will not send any events. + * register_error_listener?: bool|Param, // Default: true + * register_error_handler?: bool|Param, // Default: true + * logger?: scalar|Param|null, // The service ID of the PSR-3 logger used to log messages coming from the SDK client. Be aware that setting the same logger of the application may create a circular loop when an event fails to be sent. // Default: null + * options?: array{ + * integrations?: mixed, // Default: [] + * default_integrations?: bool|Param, + * prefixes?: list, + * sample_rate?: float|Param, // The sampling factor to apply to events. A value of 0 will deny sending any event, and a value of 1 will send all events. + * enable_tracing?: bool|Param, + * traces_sample_rate?: float|Param, // The sampling factor to apply to transactions. A value of 0 will deny sending any transaction, and a value of 1 will send all transactions. + * traces_sampler?: scalar|Param|null, + * profiles_sample_rate?: float|Param, // The sampling factor to apply to profiles. A value of 0 will deny sending any profiles, and a value of 1 will send all profiles. Profiles are sampled in relation to traces_sample_rate + * enable_logs?: bool|Param, + * enable_metrics?: bool|Param, // Default: true + * attach_stacktrace?: bool|Param, + * attach_metric_code_locations?: bool|Param, + * context_lines?: int|Param, + * environment?: scalar|Param|null, // Default: "%kernel.environment%" + * logger?: scalar|Param|null, + * spotlight?: bool|Param, + * spotlight_url?: scalar|Param|null, + * release?: scalar|Param|null, // Default: "%env(default::SENTRY_RELEASE)%" + * server_name?: scalar|Param|null, + * ignore_exceptions?: list, + * ignore_transactions?: list, + * before_send?: scalar|Param|null, + * before_send_transaction?: scalar|Param|null, + * before_send_check_in?: scalar|Param|null, + * before_send_metrics?: scalar|Param|null, + * before_send_log?: scalar|Param|null, + * before_send_metric?: scalar|Param|null, + * trace_propagation_targets?: mixed, + * tags?: array, + * error_types?: scalar|Param|null, + * max_breadcrumbs?: int|Param, + * before_breadcrumb?: mixed, + * in_app_exclude?: list, + * in_app_include?: list, + * send_default_pii?: bool|Param, + * max_value_length?: int|Param, + * transport?: scalar|Param|null, + * http_client?: scalar|Param|null, + * http_proxy?: scalar|Param|null, + * http_proxy_authentication?: scalar|Param|null, + * http_connect_timeout?: float|Param, // The maximum number of seconds to wait while trying to connect to a server. It works only when using the default transport. + * http_timeout?: float|Param, // The maximum execution time for the request+response as a whole. It works only when using the default transport. + * http_ssl_verify_peer?: bool|Param, + * http_compression?: bool|Param, + * capture_silenced_errors?: bool|Param, + * max_request_body_size?: "none"|"never"|"small"|"medium"|"always"|Param, + * class_serializers?: array, + * }, + * messenger?: bool|array{ + * enabled?: bool|Param, // Default: true + * capture_soft_fails?: bool|Param, // Default: true + * isolate_breadcrumbs_by_message?: bool|Param, // Default: false + * }, + * tracing?: bool|array{ + * enabled?: bool|Param, // Default: true + * dbal?: bool|array{ + * enabled?: bool|Param, // Default: true + * connections?: list, + * }, + * twig?: bool|array{ + * enabled?: bool|Param, // Default: true + * }, + * cache?: bool|array{ + * enabled?: bool|Param, // Default: true + * }, + * http_client?: bool|array{ + * enabled?: bool|Param, // Default: true + * }, + * console?: array{ + * excluded_commands?: list, + * }, + * }, + * } + * @psalm-type VichUploaderConfig = array{ + * default_filename_attribute_suffix?: scalar|Param|null, // Default: "_name" + * db_driver: scalar|Param|null, + * storage?: scalar|Param|null, // Default: "file_system" + * use_flysystem_to_resolve_uri?: bool|Param, // Default: false + * twig?: scalar|Param|null, // twig requires templating // Default: true + * form?: scalar|Param|null, // Default: true + * metadata?: array{ + * cache?: scalar|Param|null, // Default: "file" + * type?: scalar|Param|null, // Default: "attribute" + * file_cache?: array{ + * dir?: scalar|Param|null, // Default: "%kernel.cache_dir%/vich_uploader" + * }, + * auto_detection?: bool|Param, // Default: true + * directories?: list, + * }, + * mappings?: array, + * } + * @psalm-type KnpuOauth2ClientConfig = array{ + * http_client?: scalar|Param|null, // Service id of HTTP client to use (must implement GuzzleHttp\ClientInterface) // Default: null + * http_client_options?: array{ + * timeout?: int|Param, + * proxy?: scalar|Param|null, + * verify?: bool|Param, // Use only with proxy option set + * }, + * clients?: array>, + * } + * @psalm-type SchebTwoFactorConfig = array{ + * persister?: scalar|Param|null, // Default: "scheb_two_factor.persister.doctrine" + * model_manager_name?: scalar|Param|null, // Default: null + * security_tokens?: list, + * ip_whitelist?: list, + * ip_whitelist_provider?: scalar|Param|null, // Default: "scheb_two_factor.default_ip_whitelist_provider" + * two_factor_token_factory?: scalar|Param|null, // Default: "scheb_two_factor.default_token_factory" + * two_factor_provider_decider?: scalar|Param|null, // Default: "scheb_two_factor.default_provider_decider" + * two_factor_condition?: scalar|Param|null, // Default: null + * code_reuse_cache?: scalar|Param|null, // Default: null + * code_reuse_cache_duration?: int|Param, // Default: 60 + * code_reuse_default_handler?: scalar|Param|null, // Default: null + * backup_codes?: bool|array{ + * enabled?: scalar|Param|null, // Default: false + * manager?: scalar|Param|null, // Default: "scheb_two_factor.default_backup_code_manager" + * }, + * email?: bool|array{ + * enabled?: scalar|Param|null, // Default: false + * mailer?: scalar|Param|null, // Default: null + * code_generator?: scalar|Param|null, // Default: "scheb_two_factor.security.email.default_code_generator" + * form_renderer?: scalar|Param|null, // Default: null + * sender_email?: scalar|Param|null, // Default: null + * sender_name?: scalar|Param|null, // Default: null + * template?: scalar|Param|null, // Default: "@SchebTwoFactor/Authentication/form.html.twig" + * digits?: int|Param, // Default: 4 + * }, + * google?: bool|array{ + * enabled?: scalar|Param|null, // Default: false + * form_renderer?: scalar|Param|null, // Default: null + * issuer?: scalar|Param|null, // Default: null + * server_name?: scalar|Param|null, // Default: null + * template?: scalar|Param|null, // Default: "@SchebTwoFactor/Authentication/form.html.twig" + * digits?: int|Param, // Default: 6 + * leeway?: int|Param, // Default: 0 + * }, + * } + * @psalm-type NelmioSecurityConfig = array{ + * signed_cookie?: array{ + * names?: list, + * secret?: scalar|Param|null, // Default: "%kernel.secret%" + * hash_algo?: scalar|Param|null, + * legacy_hash_algo?: scalar|Param|null, // Fallback algorithm to allow for frictionless hash algorithm upgrades. Use with caution and as a temporary measure as it allows for downgrade attacks. // Default: null + * separator?: scalar|Param|null, // Default: "." + * }, + * clickjacking?: array{ + * hosts?: list, + * paths?: array, + * content_types?: list, + * }, + * external_redirects?: array{ + * abort?: bool|Param, // Default: false + * override?: scalar|Param|null, // Default: null + * forward_as?: scalar|Param|null, // Default: null + * log?: bool|Param, // Default: false + * allow_list?: list, + * }, + * flexible_ssl?: bool|array{ + * enabled?: bool|Param, // Default: false + * cookie_name?: scalar|Param|null, // Default: "auth" + * unsecured_logout?: bool|Param, // Default: false + * }, + * forced_ssl?: bool|array{ + * enabled?: bool|Param, // Default: false + * hsts_max_age?: scalar|Param|null, // Default: null + * hsts_subdomains?: bool|Param, // Default: false + * hsts_preload?: bool|Param, // Default: false + * allow_list?: list, + * hosts?: list, + * redirect_status_code?: scalar|Param|null, // Default: 302 + * }, + * content_type?: array{ + * nosniff?: bool|Param, // Default: false + * }, + * xss_protection?: array{ // Deprecated: The "xss_protection" option is deprecated, use Content Security Policy without allowing "unsafe-inline" scripts instead. + * enabled?: bool|Param, // Default: false + * mode_block?: bool|Param, // Default: false + * report_uri?: scalar|Param|null, // Default: null + * }, + * csp?: bool|array{ + * enabled?: bool|Param, // Default: true + * request_matcher?: scalar|Param|null, // Default: null + * hosts?: list, + * content_types?: list, + * report_endpoint?: array{ + * log_channel?: scalar|Param|null, // Default: null + * log_formatter?: scalar|Param|null, // Default: "nelmio_security.csp_report.log_formatter" + * log_level?: "alert"|"critical"|"debug"|"emergency"|"error"|"info"|"notice"|"warning"|Param, // Default: "notice" + * filters?: array{ + * domains?: bool|Param, // Default: true + * schemes?: bool|Param, // Default: true + * browser_bugs?: bool|Param, // Default: true + * injected_scripts?: bool|Param, // Default: true + * }, + * dismiss?: list>, + * }, + * compat_headers?: bool|Param, // Default: true + * report_logger_service?: scalar|Param|null, // Default: "logger" + * hash?: array{ + * algorithm?: "sha256"|"sha384"|"sha512"|Param, // The algorithm to use for hashes // Default: "sha256" + * }, + * report?: array{ + * level1_fallback?: bool|Param, // Provides CSP Level 1 fallback when using hash or nonce (CSP level 2) by adding 'unsafe-inline' source. See https://www.w3.org/TR/CSP2/#directive-script-src and https://www.w3.org/TR/CSP2/#directive-style-src // Default: true + * browser_adaptive?: bool|array{ // Do not send directives that browser do not support + * enabled?: bool|Param, // Default: false + * parser?: scalar|Param|null, // Default: "nelmio_security.ua_parser.ua_php" + * }, + * default-src?: list, + * base-uri?: list, + * block-all-mixed-content?: bool|Param, // Default: false + * child-src?: list, + * connect-src?: list, + * font-src?: list, + * form-action?: list, + * frame-ancestors?: list, + * frame-src?: list, + * img-src?: list, + * manifest-src?: list, + * media-src?: list, + * object-src?: list, + * plugin-types?: list, + * script-src?: list, + * style-src?: list, + * upgrade-insecure-requests?: bool|Param, // Default: false + * report-uri?: list, + * worker-src?: list, + * prefetch-src?: list, + * report-to?: scalar|Param|null, + * }, + * enforce?: array{ + * level1_fallback?: bool|Param, // Provides CSP Level 1 fallback when using hash or nonce (CSP level 2) by adding 'unsafe-inline' source. See https://www.w3.org/TR/CSP2/#directive-script-src and https://www.w3.org/TR/CSP2/#directive-style-src // Default: true + * browser_adaptive?: bool|array{ // Do not send directives that browser do not support + * enabled?: bool|Param, // Default: false + * parser?: scalar|Param|null, // Default: "nelmio_security.ua_parser.ua_php" + * }, + * default-src?: list, + * base-uri?: list, + * block-all-mixed-content?: bool|Param, // Default: false + * child-src?: list, + * connect-src?: list, + * font-src?: list, + * form-action?: list, + * frame-ancestors?: list, + * frame-src?: list, + * img-src?: list, + * manifest-src?: list, + * media-src?: list, + * object-src?: list, + * plugin-types?: list, + * script-src?: list, + * style-src?: list, + * upgrade-insecure-requests?: bool|Param, // Default: false + * report-uri?: list, + * worker-src?: list, + * prefetch-src?: list, + * report-to?: scalar|Param|null, + * }, + * }, + * referrer_policy?: bool|array{ + * enabled?: bool|Param, // Default: false + * policies?: list, + * }, + * permissions_policy?: bool|array{ + * enabled?: bool|Param, // Default: false + * policies?: array{ + * accelerometer?: mixed, // Default: null + * ambient_light_sensor?: mixed, // Default: null + * attribution_reporting?: mixed, // Default: null + * autoplay?: mixed, // Default: null + * bluetooth?: mixed, // Default: null + * browsing_topics?: mixed, // Default: null + * camera?: mixed, // Default: null + * captured_surface_control?: mixed, // Default: null + * compute_pressure?: mixed, // Default: null + * cross_origin_isolated?: mixed, // Default: null + * deferred_fetch?: mixed, // Default: null + * deferred_fetch_minimal?: mixed, // Default: null + * display_capture?: mixed, // Default: null + * encrypted_media?: mixed, // Default: null + * fullscreen?: mixed, // Default: null + * gamepad?: mixed, // Default: null + * geolocation?: mixed, // Default: null + * gyroscope?: mixed, // Default: null + * hid?: mixed, // Default: null + * identity_credentials_get?: mixed, // Default: null + * idle_detection?: mixed, // Default: null + * interest_cohort?: mixed, // Default: null + * language_detector?: mixed, // Default: null + * local_fonts?: mixed, // Default: null + * magnetometer?: mixed, // Default: null + * microphone?: mixed, // Default: null + * midi?: mixed, // Default: null + * otp_credentials?: mixed, // Default: null + * payment?: mixed, // Default: null + * picture_in_picture?: mixed, // Default: null + * publickey_credentials_create?: mixed, // Default: null + * publickey_credentials_get?: mixed, // Default: null + * screen_wake_lock?: mixed, // Default: null + * serial?: mixed, // Default: null + * speaker_selection?: mixed, // Default: null + * storage_access?: mixed, // Default: null + * summarizer?: mixed, // Default: null + * translator?: mixed, // Default: null + * usb?: mixed, // Default: null + * web_share?: mixed, // Default: null + * window_management?: mixed, // Default: null + * xr_spatial_tracking?: mixed, // Default: null + * }, + * }, + * cross_origin_isolation?: bool|array{ + * enabled?: bool|Param, // Default: false + * paths?: array, + * }, + * } + * @psalm-type PwaConfig = array{ + * asset_compiler?: bool|Param, // When true, the assets will be compiled when the command "asset-map:compile" is run. // Default: true + * early_hints?: bool|array{ // Early Hints (HTTP 103) configuration. Requires a compatible server (FrankenPHP, Caddy). + * enabled?: bool|Param, // Default: false + * preload_manifest?: bool|Param, // Preload the PWA manifest file. // Default: true + * preload_serviceworker?: bool|Param, // Preload the service worker script. Disabled by default as SW registration is usually deferred. // Default: false + * preconnect_workbox_cdn?: bool|Param, // Preconnect to Workbox CDN when using CDN mode. // Default: true + * }, + * favicons?: bool|array{ + * enabled?: bool|Param, // Default: false + * default?: array{ // The favicon source and parameters. When used with "dark", this favicon will become the light version. + * src: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed). + * background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null + * border_radius?: int|Param, // The border radius of the icon. // Default: null + * image_scale?: int|Param, // The scale of the icon. // Default: null + * svg_attr?: array, + * }, + * dark?: array{ // The favicon source and parameters for the dark theme. Should only be used with "default". + * src: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed). + * background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null + * border_radius?: int|Param, // The border radius of the icon. // Default: null + * image_scale?: int|Param, // The scale of the icon. // Default: null + * svg_attr?: array, + * }, + * src?: scalar|Param|null, // Deprecated: The "src" configuration key is deprecated. Use the "default.src" configuration key instead. // The source of the favicon. Shall be a SVG or large PNG. // Default: null + * src_dark?: scalar|Param|null, // Deprecated: The "src_dark" configuration key is deprecated. Use the "dark.src" configuration key instead. // The source of the favicon in dark mode. Shall be a SVG or large PNG. // Default: null + * background_color?: scalar|Param|null, // Deprecated: The "background_color" configuration key is deprecated. Use the "default.background_color" configuration key instead. // The background color of the icon. // Default: null + * background_color_dark?: scalar|Param|null, // Deprecated: The "background_color_dark" configuration key is deprecated. Use the "dark.background_color" configuration key instead. // The background color of the icon in dark mode. // Default: null + * safari_pinned_tab_color?: scalar|Param|null, // The color of the Safari pinned tab. Requires "use_silhouette" to be set to "true". // Default: null + * tile_color?: scalar|Param|null, // The color of the tile for Windows 8+. // Default: null + * border_radius?: int|Param, // Deprecated: The "border_radius" configuration key is deprecated. Use the "default.border_radius" or "dark.border_radius" configuration key instead. // The border radius of the icon. // Default: null + * image_scale?: int|Param, // Deprecated: The "image_scale" configuration key is deprecated. Use the "default.image_scale" or "dark.image_scale" configuration key instead. // The scale of the icon. // Default: null + * low_resolution?: bool|Param, // Include low resolution icons. // Default: false + * use_silhouette?: bool|Param|null, // Use only the silhouette of the icon. Applicable for macOS Safari and Windows 8+. Requires potrace to be installed. // Default: null + * use_start_image?: bool|Param, // Use the icon as a start image for the iOS splash screen. // Default: true + * svg_color?: scalar|Param|null, // When the asset is a SVG file, replaces the currentColor attribute with this color. // Default: "#000" + * monochrome?: bool|Param, // Use a monochrome icon. // Default: false + * potrace?: scalar|Param|null, // The path to the potrace binary. // Default: "potrace" + * }, + * image_processor?: scalar|Param|null, // The image processor to use to generate the icons of different sizes. // Default: null + * logger?: scalar|Param|null, // The logger service to use. If not set, the default logger will be used. // Default: null + * manifest?: bool|array{ + * enabled?: bool|Param, // Default: false + * public_url?: scalar|Param|null, // The public URL of the manifest file. // Default: "/site.webmanifest" + * use_credentials?: bool|Param, // Indicates whether the manifest should be fetched with credentials. // Default: true + * background_color?: scalar|Param|null, // The background color of the application. It should match the background-color CSS property in the sites stylesheet for a smooth transition between launching the web application and loading the site's content. + * categories?: list, + * description?: scalar|Param|null, // The description of the application. + * display?: scalar|Param|null, // The display mode of the application. + * display_override?: list, + * id?: scalar|Param|null, // A string that represents the identity of the web application. + * orientation?: scalar|Param|null, // The orientation of the application. + * dir?: scalar|Param|null, // The direction of the application. + * lang?: scalar|Param|null, // The language of the application. + * name?: scalar|Param|null, // The name of the application. + * short_name?: scalar|Param|null, // The short name of the application. + * scope?: scalar|Param|null, // The scope of the application. + * start_url?: string|array{ // The start URL of the application. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * theme_color?: scalar|Param|null, // The theme color of the application. If a dark theme color is specified, the theme color will be used for the light theme. + * dark_theme_color?: scalar|Param|null, // The dark theme color of the application. + * edge_side_panel?: array{ // Specifies whether or not your app supports the side panel view in Microsoft Edge. + * preferred_width?: int|Param, // Specifies the preferred width of the side panel view in Microsoft Edge. + * }, + * iarc_rating_id?: scalar|Param|null, // Specifies the International Age Rating Coalition (IARC) rating ID for the app. See https://www.globalratings.com/how-iarc-works.aspx for more information. + * scope_extensions?: list, + * handle_links?: scalar|Param|null, // Specifies the default link handling for the web app. + * note_taking?: array{ // The note-taking capabilities of the application. + * note_taking_url?: string|array{ // The URL to the note-taking service. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * }, + * icons?: list, + * background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null + * border_radius?: int|Param, // The border radius of the icon. // Default: null + * image_scale?: int|Param, // The scale of the icon. // Default: null + * type?: scalar|Param|null, // The icon mime type. + * format?: scalar|Param|null, // The icon format. When set, the "type" option is ignored and the image will be converted. + * purpose?: scalar|Param|null, // The purpose of the icon. + * svg_attr?: array, + * }>, + * screenshots?: list, + * file_handlers?: list, + * }, + * accept?: array>, + * }>, + * launch_handler?: array{ // The launch handler of the application. + * client_mode?: list, + * }, + * protocol_handlers?: list, + * }, + * }>, + * prefer_related_applications?: bool|Param, // prefer related native applications (instead of this application) // Default: false + * related_applications?: list, + * }, + * id?: scalar|Param|null, // The ID of the application. + * }>, + * shortcuts?: list, + * }, + * icons?: list, + * background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null + * border_radius?: int|Param, // The border radius of the icon. // Default: null + * image_scale?: int|Param, // The scale of the icon. // Default: null + * type?: scalar|Param|null, // The icon mime type. + * format?: scalar|Param|null, // The icon format. When set, the "type" option is ignored and the image will be converted. + * purpose?: scalar|Param|null, // The purpose of the icon. + * svg_attr?: array, + * }>, + * }>, + * share_target?: array{ // The share target of the application. + * action?: string|array{ // The action of the share target. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * method?: scalar|Param|null, // The method of the share target. + * enctype?: scalar|Param|null, // The enctype of the share target. Ignored if method is GET. + * params: array{ // The parameters of the share target. + * title?: scalar|Param|null, // The title of the share target. + * text?: scalar|Param|null, // The text of the share target. + * url?: scalar|Param|null, // The URL of the share target. + * files?: list, + * }>, + * }, + * }, + * widgets?: list, + * background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null + * border_radius?: int|Param, // The border radius of the icon. // Default: null + * image_scale?: int|Param, // The scale of the icon. // Default: null + * type?: scalar|Param|null, // The icon mime type. + * format?: scalar|Param|null, // The icon format. When set, the "type" option is ignored and the image will be converted. + * purpose?: scalar|Param|null, // The purpose of the icon. + * svg_attr?: array, + * }>, + * screenshots?: list, + * tag: scalar|Param|null, // A string used to reference the widget in the PWA service worker. + * template?: scalar|Param|null, // The template to use to display the widget in the operating system widgets dashboard. Note: this property is currently only informational and not used. See ms_ac_template below. + * ms_ac_template?: string|array{ // The URL of the custom Adaptive Cards template to use to display the widget in the operating system widgets dashboard. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * data?: string|array{ // The URL where the data to fill the template with can be found. If present, this URL is required to return valid JSON. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * type?: scalar|Param|null, // The MIME type for the widget data. + * auth?: bool|Param, // A boolean indicating if the widget requires authentication. + * update?: int|Param, // The frequency, in seconds, at which the widget will be updated. Code in your service worker must perform the updating; the widget is not updated automatically. See Access widget instances at runtime. + * multiple?: bool|Param, // A boolean indicating whether to allow multiple instances of the widget. Defaults to true. // Default: true + * }>, + * }, + * path_type_reference?: int|Param, // Deprecated: The "path_type_reference" configuration key is deprecated. Use the "path_type_reference" of URL nodes instead. // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * resource_hints?: bool|array{ // Resource Hints configuration for preconnect, dns-prefetch, and preload. + * enabled?: bool|Param, // Default: false + * auto_preconnect?: bool|Param, // Automatically add preconnect hints for detected external origins (Workbox CDN, Google Fonts). // Default: true + * preconnect?: list, + * dns_prefetch?: list, + * preload?: list, + * }, + * serviceworker?: bool|string|array{ + * enabled?: bool|Param, // Default: false + * src?: scalar|Param|null, // The path to the service worker source file. Can be served by Asset Mapper. + * dest?: scalar|Param|null, // The public URL to the service worker. // Default: "/sw.js" + * skip_waiting?: bool|Param, // Whether to skip waiting for the service worker to be activated. // Default: false + * scope?: scalar|Param|null, // The scope of the service worker. // Default: "/" + * use_cache?: bool|Param, // Whether the service worker should use the cache. // Default: true + * workbox?: bool|array{ // The configuration of the workbox. + * enabled?: bool|Param, // Default: true + * use_cdn?: bool|Param, // Deprecated: The "use_cdn" option is deprecated and will be removed in 2.0.0. use "config.use_cdn" instead. // Whether to use the local workbox or the CDN. // Default: false + * google_fonts?: bool|array{ + * enabled?: bool|Param, // Default: true + * cache_prefix?: scalar|Param|null, // The cache prefix for the Google fonts. // Default: null + * max_age?: scalar|Param|null, // The maximum age of the Google fonts cache (in seconds). // Default: null + * max_entries?: int|Param, // The maximum number of entries in the Google fonts cache. // Default: null + * }, + * cache_manifest?: bool|Param, // Whether to cache the manifest file. // Default: true + * version?: scalar|Param|null, // Deprecated: The "version" option is deprecated and will be removed in 2.0.0. use "config.version" instead. // The version of workbox. When using local files, the version shall be "7.0.0." // Default: "7.3.0" + * workbox_public_url?: scalar|Param|null, // Deprecated: The "workbox_public_url" option is deprecated and will be removed in 2.0.0. use "config.workbox_public_url" instead. // The public path to the local workbox. Only used if use_cdn is false. // Default: "/workbox" + * idb_public_url?: scalar|Param|null, // The public path to the local IndexDB. Only used if use_cdn is false. // Default: "/idb" + * workbox_import_placeholder?: scalar|Param|null, // Deprecated: The "workbox_import_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the workbox import. Will be replaced by the workbox import. // Default: "//WORKBOX_IMPORT_PLACEHOLDER" + * standard_rules_placeholder?: scalar|Param|null, // Deprecated: The "standard_rules_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the standard rules. Will be replaced by caching strategies. // Default: "//STANDARD_RULES_PLACEHOLDER" + * offline_fallback_placeholder?: scalar|Param|null, // Deprecated: The "offline_fallback_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the offline fallback. Will be replaced by the URL. // Default: "//OFFLINE_FALLBACK_PLACEHOLDER" + * widgets_placeholder?: scalar|Param|null, // Deprecated: The "widgets_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the widgets. Will be replaced by the widgets management events. // Default: "//WIDGETS_PLACEHOLDER" + * clear_cache?: bool|Param, // Whether to clear the cache during the service worker activation. // Default: true + * navigation_preload?: bool|Param, // Whether to enable navigation preload. This speeds up navigation requests by making the network request in parallel with service worker boot-up. Note: Do not enable if you are precaching HTML pages (e.g., with offline_fallback or warm_cache_urls), as it would be redundant. // Default: false + * config?: array{ + * debug?: bool|Param, // Controls workbox debug logging. Set to false to disable debug mode and logging. // Default: true + * version?: scalar|Param|null, // The version of workbox. When using local files, the version shall be "7.0.0." // Default: "7.3.0" + * use_cdn?: bool|Param, // Whether to use the local workbox or the CDN. // Default: false + * workbox_public_url?: scalar|Param|null, // The public path to the local workbox. Only used if use_cdn is false. // Default: "/workbox" + * }, + * offline_fallback?: array{ + * cache_name?: scalar|Param|null, // The name of the offline cache. // Default: "offline" + * page?: string|array{ // The URL of the offline page fallback. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * image?: string|array{ // The URL of the offline image fallback. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * font?: string|array{ // The URL of the offline font fallback. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * }, + * image_cache?: bool|array{ + * enabled?: bool|Param, // Default: true + * cache_name?: scalar|Param|null, // The name of the image cache. // Default: "images" + * regex?: scalar|Param|null, // The regex to match the images. // Default: "/\\.(ico|png|jpe?g|gif|svg|webp|bmp)$/" + * max_entries?: int|Param, // The maximum number of entries in the image cache. // Default: 60 + * max_age?: scalar|Param|null, // The maximum number of seconds before the image cache is invalidated. // Default: 31536000 + * }, + * asset_cache?: bool|array{ + * enabled?: bool|Param, // Default: true + * cache_name?: scalar|Param|null, // The name of the asset cache. // Default: "assets" + * regex?: scalar|Param|null, // The regex to match the assets. // Default: "/\\.(css|js|json|xml|txt|map|ico|png|jpe?g|gif|svg|webp|bmp)$/" + * max_age?: scalar|Param|null, // The maximum number of seconds before the asset cache is invalidated. // Default: 31536000 + * }, + * font_cache?: bool|array{ + * enabled?: bool|Param, // Default: true + * cache_name?: scalar|Param|null, // The name of the font cache. // Default: "fonts" + * regex?: scalar|Param|null, // The regex to match the fonts. // Default: "/\\.(ttf|eot|otf|woff2)$/" + * max_entries?: int|Param, // The maximum number of entries in the image cache. // Default: 60 + * max_age?: int|Param, // The maximum number of seconds before the font cache is invalidated. // Default: 31536000 + * }, + * resource_caches?: list, + * cacheable_response_statuses?: list, + * broadcast_headers?: list, + * preload_urls?: list, + * }>, + * }>, + * background_sync?: list, + * expect_redirect?: bool|Param, // Whether to expect a redirect (JS response type should be "opaqueredirect" or the "redirected" property is "true"). // Default: false + * method?: scalar|Param|null, // The HTTP method. // Default: "POST" + * broadcast_channel?: scalar|Param|null, // The broadcast channel. Set null to disable. // Default: null + * max_retention_time?: int|Param, // The maximum retention time in minutes. // Default: 1440 + * force_sync_fallback?: bool|Param, // If `true`, instead of attempting to use background sync events, always attempt to replay queued request at service worker startup. Most folks will not need this, unless you explicitly target a runtime like Electron that exposes the interfaces for background sync, but does not have a working implementation. // Default: false + * }>, + * background_fetch?: bool|array{ + * enabled?: bool|Param, // Default: false + * db_name?: scalar|Param|null, // The IndexDB name where downloads are stored // Default: "bgfetch-completed" + * progress_url?: string|array{ // The URL of the progress page. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * success_url?: string|array{ // The URL of the success page. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * success_message?: scalar|Param|null, // The message to display on success. This message is translated. // Default: null + * failure_message?: scalar|Param|null, // The message to display on success. This message is translated. // Default: null + * }, + * image_cache_name?: scalar|Param|null, // Deprecated: The "image_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.cache_name" instead. // The name of the image cache. // Default: "images" + * font_cache_name?: scalar|Param|null, // Deprecated: The "font_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.cache_name" instead. // The name of the font cache. // Default: "fonts" + * page_cache_name?: scalar|Param|null, // Deprecated: The "page_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.resource_caches[].cache_name" instead. // The name of the page cache. // Default: "pages" + * asset_cache_name?: scalar|Param|null, // Deprecated: The "asset_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.asset_cache.cache_name" instead. // The name of the asset cache. // Default: "assets" + * page_fallback?: string|array{ // The URL of the offline page fallback. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * image_fallback?: string|array{ // The URL of the offline image fallback. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * font_fallback?: string|array{ // The URL of the offline font fallback. + * path: scalar|Param|null, // The URL or route name. + * path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1 + * params?: list, + * }, + * image_regex?: scalar|Param|null, // Deprecated: The "image_regex" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.regex" instead. // The regex to match the images. // Default: "/\\.(ico|png|jpe?g|gif|svg|webp|bmp)$/" + * static_regex?: scalar|Param|null, // Deprecated: The "static_regex" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.asset_cache.regex" instead. // The regex to match the static files. // Default: "/\\.(css|js|json|xml|txt|map)$/" + * font_regex?: scalar|Param|null, // Deprecated: The "font_regex" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.regex" instead. // The regex to match the static files. // Default: "/\\.(ttf|eot|otf|woff2)$/" + * max_image_cache_entries?: int|Param, // Deprecated: The "max_image_cache_entries" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.max_entries" instead. // The maximum number of entries in the image cache. // Default: 60 + * max_image_age?: int|Param, // Deprecated: The "max_image_age" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.max_age" instead. // The maximum number of seconds before the image cache is invalidated. // Default: 31536000 + * max_font_cache_entries?: int|Param, // Deprecated: The "max_font_cache_entries" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.max_entries" instead. // The maximum number of entries in the font cache. // Default: 30 + * max_font_age?: int|Param, // Deprecated: The "max_font_age" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.max_age" instead. // The maximum number of seconds before the font cache is invalidated. // Default: 31536000 + * network_timeout_seconds?: int|Param, // Deprecated: The "network_timeout_seconds" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.resource_caches[].network_timeout" instead. // The network timeout in seconds before cache is called (for warm cache URLs only). // Default: 3 + * warm_cache_urls?: list, + * }>, + * }, + * }, + * speculation_rules?: bool|array{ // Speculation Rules API configuration for prefetching and prerendering pages. + * enabled?: bool|Param, // Default: false + * prefetch?: list, + * }>, + * selector_matches?: scalar|Param|null, // For "document" source: CSS selector to match links. // Default: null + * href_matches?: scalar|Param|null, // For "document" source: URL pattern to match href attributes. // Default: null + * eagerness?: "immediate"|"eager"|"moderate"|"conservative"|Param, // Eagerness level: "immediate" (viewport), "eager" (hover 200ms), "moderate" (hover 100ms), "conservative" (mousedown/touchstart). // Default: "moderate" + * referrer_policy?: scalar|Param|null, // Referrer policy for the speculative request. // Default: null + * }>, + * prerender?: list, + * }>, + * selector_matches?: scalar|Param|null, // For "document" source: CSS selector to match links. // Default: null + * href_matches?: scalar|Param|null, // For "document" source: URL pattern to match href attributes. // Default: null + * eagerness?: "immediate"|"eager"|"moderate"|"conservative"|Param, // Eagerness level. For prerender, "conservative" is recommended. // Default: "conservative" + * referrer_policy?: scalar|Param|null, // Referrer policy for the speculative request. // Default: null + * }>, + * }, + * web_client?: scalar|Param|null, // The Panther Client for generating screenshots. If not set, the default client will be used. // Default: null + * user_agent?: scalar|Param|null, // The user agent to use when generating screenshots. When this user agent is detected, the Symfony profiler and debug toolbar will be automatically disabled to ensure screenshots look like production. // Default: "PWAScreenshotBot" + * } + * @psalm-type WebpushConfig = array{ + * logger?: scalar|Param|null, // A PSR3 logger to receive logs // Default: null + * http_client?: scalar|Param|null, // PSR18 client to send notification to Web Push Services // Default: "Symfony\\Contracts\\HttpClient\\HttpClientInterface" + * vapid?: bool|array{ + * enabled?: bool|Param, // Default: false + * subject: scalar|Param|null, // The URL of the service or an email address + * token_lifetime?: scalar|Param|null, // A PSR6 cache pool to enable caching feature // Default: "now +1hour" + * web_token?: bool|array{ + * enabled?: bool|Param, // Default: false + * private_key: scalar|Param|null, // The VAPID private key + * public_key: scalar|Param|null, // The VAPID public key + * }, + * lcobucci?: bool|array{ + * enabled?: bool|Param, // Default: false + * private_key: scalar|Param|null, // The VAPID private key + * public_key: scalar|Param|null, // The VAPID public key + * }, + * custom?: bool|array{ + * enabled?: bool|Param, // Default: false + * id: scalar|Param|null, // The custom JWS Provider service ID + * }, + * }, + * payload?: array{ + * aes128gcm?: array{ + * padding?: scalar|Param|null, // Length of the padding: none, recommended, max or and integer // Default: "recommended" + * cache?: scalar|Param|null, // A PSR6 cache pool to enable caching feature // Default: null + * cache_lifetime?: scalar|Param|null, // A PSR6 cache pool to enable caching feature // Default: "now + 30min" + * }, + * aesgcm?: array{ + * padding?: scalar|Param|null, // Length of the padding: none, recommended, max or and integer // Default: "recommended" + * cache?: scalar|Param|null, // A PSR6 cache pool to enable caching feature // Default: null + * cache_lifetime?: scalar|Param|null, // A PSR6 cache pool to enable caching feature // Default: "now + 30min" + * }, + * }, * } * @psalm-type ConfigType = array{ * imports?: ImportsConfig, @@ -1517,11 +2445,20 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * doctrine?: DoctrineConfig, * doctrine_migrations?: DoctrineMigrationsConfig, * twig?: TwigConfig, - * stimulus?: StimulusConfig, - * turbo?: TurboConfig, * twig_extra?: TwigExtraConfig, * security?: SecurityConfig, * monolog?: MonologConfig, + * knp_paginator?: KnpPaginatorConfig, + * flysystem?: FlysystemConfig, + * liip_imagine?: LiipImagineConfig, + * nelmio_cors?: NelmioCorsConfig, + * presta_sitemap?: PrestaSitemapConfig, + * vich_uploader?: VichUploaderConfig, + * knpu_oauth2_client?: KnpuOauth2ClientConfig, + * scheb_two_factor?: SchebTwoFactorConfig, + * nelmio_security?: NelmioSecurityConfig, + * pwa?: PwaConfig, + * webpush?: WebpushConfig, * "when@dev"?: array{ * imports?: ImportsConfig, * parameters?: ParametersConfig, @@ -1532,12 +2469,21 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * debug?: DebugConfig, * twig?: TwigConfig, * web_profiler?: WebProfilerConfig, - * stimulus?: StimulusConfig, - * turbo?: TurboConfig, * twig_extra?: TwigExtraConfig, * security?: SecurityConfig, * monolog?: MonologConfig, * maker?: MakerConfig, + * knp_paginator?: KnpPaginatorConfig, + * flysystem?: FlysystemConfig, + * liip_imagine?: LiipImagineConfig, + * nelmio_cors?: NelmioCorsConfig, + * presta_sitemap?: PrestaSitemapConfig, + * vich_uploader?: VichUploaderConfig, + * knpu_oauth2_client?: KnpuOauth2ClientConfig, + * scheb_two_factor?: SchebTwoFactorConfig, + * nelmio_security?: NelmioSecurityConfig, + * pwa?: PwaConfig, + * webpush?: WebpushConfig, * }, * "when@prod"?: array{ * imports?: ImportsConfig, @@ -1547,11 +2493,21 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * doctrine?: DoctrineConfig, * doctrine_migrations?: DoctrineMigrationsConfig, * twig?: TwigConfig, - * stimulus?: StimulusConfig, - * turbo?: TurboConfig, * twig_extra?: TwigExtraConfig, * security?: SecurityConfig, * monolog?: MonologConfig, + * knp_paginator?: KnpPaginatorConfig, + * flysystem?: FlysystemConfig, + * liip_imagine?: LiipImagineConfig, + * nelmio_cors?: NelmioCorsConfig, + * presta_sitemap?: PrestaSitemapConfig, + * sentry?: SentryConfig, + * vich_uploader?: VichUploaderConfig, + * knpu_oauth2_client?: KnpuOauth2ClientConfig, + * scheb_two_factor?: SchebTwoFactorConfig, + * nelmio_security?: NelmioSecurityConfig, + * pwa?: PwaConfig, + * webpush?: WebpushConfig, * }, * "when@test"?: array{ * imports?: ImportsConfig, @@ -1562,11 +2518,20 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * doctrine_migrations?: DoctrineMigrationsConfig, * twig?: TwigConfig, * web_profiler?: WebProfilerConfig, - * stimulus?: StimulusConfig, - * turbo?: TurboConfig, * twig_extra?: TwigExtraConfig, * security?: SecurityConfig, * monolog?: MonologConfig, + * knp_paginator?: KnpPaginatorConfig, + * flysystem?: FlysystemConfig, + * liip_imagine?: LiipImagineConfig, + * nelmio_cors?: NelmioCorsConfig, + * presta_sitemap?: PrestaSitemapConfig, + * vich_uploader?: VichUploaderConfig, + * knpu_oauth2_client?: KnpuOauth2ClientConfig, + * scheb_two_factor?: SchebTwoFactorConfig, + * nelmio_security?: NelmioSecurityConfig, + * pwa?: PwaConfig, + * webpush?: WebpushConfig, * }, * ... /usr/local/etc/php/conf.d/memory-limit.ini \ + && echo "upload_max_filesize=100M" > /usr/local/etc/php/conf.d/uploads.ini \ + && echo "post_max_size=200M" >> /usr/local/etc/php/conf.d/uploads.ini + # Créer un utilisateur et un groupe non-root pour l'application # Utilisation de useradd/groupadd pour les systèmes basés sur Debian/Ubuntu RUN groupadd -g $GID appuser && \ diff --git a/migrate_data.php b/migrate_data.php new file mode 100644 index 0000000..b05f730 --- /dev/null +++ b/migrate_data.php @@ -0,0 +1,86 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, +]; + +try { + $pdo = new PDO($dsn, $user, $pass, $options); +} catch ( PDOException $e) { + die("Connection failed: " . $e->getMessage()); +} + +echo "Connected to database.\n"; + +function migrateTable($pdo, $tableName, $columnName, $idColumn = 'id') { + echo "Checking table: $tableName, column: $columnName\n"; + + // Check if table exists + $stmt = $pdo->prepare("SELECT to_regclass(:tablename)"); + $stmt->execute(['tablename' => $tableName]); + if (!$stmt->fetchColumn()) { + echo "Table $tableName does not exist. Skipping.\n"; + return; + } + + // Select only rows that are NOT NULL. + // We also want to avoid reprocessing already JSON data if possible, but reliable detection is tricky. + // The script below checks if data is serialized first. If not, it checks if it's JSON. + $stmt = $pdo->query("SELECT $idColumn, $columnName FROM $tableName WHERE $columnName IS NOT NULL"); + + while ($row = $stmt->fetch()) { + $id = $row[$idColumn]; + $rawData = $row[$columnName]; + + // Try to unserialize + $data = @unserialize($rawData); + + // Check for unserialization success or specific serialized values + // unserialize returns false on error AND for serialized boolean false (b:0;) + $isSerialized = ($data !== false) || ($rawData === 'b:0;') || ($rawData === 'N;'); + + if ($isSerialized) { + // It was a valid serialized string + if ($rawData === 'N;') { + // Serialized null -> SQL NULL + $updateStmt = $pdo->prepare("UPDATE $tableName SET $columnName = NULL WHERE $idColumn = :id"); + $updateStmt->execute(['id' => $id]); + echo "Updated ID $id: Serialized NULL -> SQL NULL\n"; + } else { + // Convert to JSON + $jsonData = json_encode($data); + $updateStmt = $pdo->prepare("UPDATE $tableName SET $columnName = :json WHERE $idColumn = :id"); + $updateStmt->execute(['json' => $jsonData, 'id' => $id]); + echo "Updated ID $id: Serialized -> JSON\n"; + } + } else { + // Check if it is already valid JSON + json_decode($rawData); + if (json_last_error() === JSON_ERROR_NONE) { + // It is already JSON, do nothing + // echo "ID $id is already JSON. Skipping.\n"; + } else { + // It might be a plain string or corrupted data. + // For Types::ARRAY columns, data MUST be serialized. + // If we migrated to Types::JSON, data MUST be JSON. + // If neither, it's an issue. + echo "Warning: ID $id in $tableName is neither valid serialized data nor valid JSON. Raw: " . substr($rawData, 0, 50) . "...\n"; + } + } + } +} + +migrateTable($pdo, 'contrats_payments', 'card'); +migrateTable($pdo, 'formules_product_inclus', 'config'); +migrateTable($pdo, 'formules_restriction', 'restriction_config'); + +echo "Migration complete.\n"; + diff --git a/migrations/Version20260130184514.php b/migrations/Version20260130184514.php new file mode 100644 index 0000000..173b14c --- /dev/null +++ b/migrations/Version20260130184514.php @@ -0,0 +1,38 @@ +addSql('CREATE TABLE order_session (id SERIAL NOT NULL, customer_id INT DEFAULT NULL, uuid VARCHAR(255) NOT NULL, products JSON NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_263E7C9FD17F50A6 ON order_session (uuid)'); + $this->addSql('CREATE INDEX IDX_263E7C9F9395C3F3 ON order_session (customer_id)'); + $this->addSql('COMMENT ON COLUMN order_session.created_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN order_session.updated_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE order_session ADD CONSTRAINT FK_263E7C9F9395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE order_session DROP CONSTRAINT FK_263E7C9F9395C3F3'); + $this->addSql('DROP TABLE order_session'); + } +} diff --git a/migrations/Version20260130185149.php b/migrations/Version20260130185149.php new file mode 100644 index 0000000..dadea2b --- /dev/null +++ b/migrations/Version20260130185149.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE order_session ADD state VARCHAR(50) NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE order_session DROP state'); + } +} diff --git a/migrations/Version20260131103521.php b/migrations/Version20260131103521.php new file mode 100644 index 0000000..7d351f4 --- /dev/null +++ b/migrations/Version20260131103521.php @@ -0,0 +1,58 @@ +addSql('ALTER TABLE order_session ADD billing_address VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD billing_zip_code VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD billing_town VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD adress_event VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD adress2_event VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD adress3_event VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD zip_code_event VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD town_event VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD type VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD details TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD type_sol VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD pente VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD access TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE order_session ADD distance_power DOUBLE PRECISION DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE order_session DROP billing_address'); + $this->addSql('ALTER TABLE order_session DROP billing_zip_code'); + $this->addSql('ALTER TABLE order_session DROP billing_town'); + $this->addSql('ALTER TABLE order_session DROP adress_event'); + $this->addSql('ALTER TABLE order_session DROP adress2_event'); + $this->addSql('ALTER TABLE order_session DROP adress3_event'); + $this->addSql('ALTER TABLE order_session DROP zip_code_event'); + $this->addSql('ALTER TABLE order_session DROP town_event'); + $this->addSql('ALTER TABLE order_session DROP type'); + $this->addSql('ALTER TABLE order_session DROP details'); + $this->addSql('ALTER TABLE order_session DROP type_sol'); + $this->addSql('ALTER TABLE order_session DROP pente'); + $this->addSql('ALTER TABLE order_session DROP access'); + $this->addSql('ALTER TABLE order_session DROP distance_power'); + } +} diff --git a/phpunit.dist.xml b/phpunit.dist.xml index 8d8c323..7feac31 100644 --- a/phpunit.dist.xml +++ b/phpunit.dist.xml @@ -7,6 +7,7 @@ failOnDeprecation="false" failOnNotice="false" failOnWarning="false" + displayDetailsOnTestsThatTriggerNotices="true" bootstrap="tests/bootstrap.php" cacheDirectory=".phpunit.cache" > @@ -14,7 +15,6 @@ - @@ -25,7 +25,6 @@ diff --git a/src/Controller/ReserverController.php b/src/Controller/ReserverController.php index d006249..19b7555 100644 --- a/src/Controller/ReserverController.php +++ b/src/Controller/ReserverController.php @@ -10,6 +10,7 @@ use App\Entity\SitePerformance; use App\Repository\CustomerRepository; use App\Repository\CustomerTrackingRepository; use App\Repository\FormulesRepository; +use App\Repository\OrderSessionRepository; use App\Repository\ProductRepository; use App\Repository\ProductReserveRepository; use App\Service\Mailer\Mailer; @@ -60,9 +61,9 @@ class ReserverController extends AbstractController #[Route('/produit/check', name: 'produit_check', methods: ['GET', 'POST'])] public function productCheck(Request $request, ProductReserveRepository $productReserveRepository, ProductRepository $productRepository): Response { - $productId = $request->get('id'); - $startStr = $request->get('start'); - $endStr = $request->get('end'); + $productId = $request->query->get('id'); + $startStr = $request->query->get('start'); + $endStr = $request->query->get('end'); if (!$productId && $request->isMethod('POST')) { $payload = $request->getPayload(); @@ -197,6 +198,160 @@ class ReserverController extends AbstractController ]); } + #[Route('/reservation/session', name: 'reservation_session_create', methods: ['POST'])] + public function createSession(Request $request, EntityManagerInterface $em, OrderSessionRepository $sessionRepository): Response + { + $data = json_decode($request->getContent(), true); + $existingUuid = $request->getSession()->get('order_session_uuid'); + $session = null; + + if ($existingUuid) { + $session = $sessionRepository->findOneBy(['uuid' => $existingUuid]); + } + + if (!$session) { + $session = new \App\Entity\OrderSession(); + $session->setUuid(\Symfony\Component\Uid\Uuid::v4()->toRfc4122()); + $session->setState('created'); + } + + $session->setProducts($data ?? []); + + $user = $this->getUser(); + if ($user instanceof Customer) { + $session->setCustomer($user); + } + + $em->persist($session); + $em->flush(); + + $request->getSession()->set('order_session_uuid', $session->getUuid()); + + return new JsonResponse([ + 'flowUrl' => $this->generateUrl('reservation_flow', ['sessionId' => $session->getUuid()]) + ]); + } + + #[Route('/flow/{sessionId}', name: 'reservation_flow', methods: ['GET', 'POST'])] + public function flowLogin( + string $sessionId, + AuthenticationUtils $authenticationUtils, + OrderSessionRepository $repository, + ProductRepository $productRepository, + UploaderHelper $uploaderHelper + ): Response { + // This is the POST target for the login form, but also the GET page. + // The authenticator handles the POST. For GET, we just render the page. + $session = $repository->findOneBy(['uuid' => $sessionId]); + if (!$session) { + return $this->render('revervation/session_lost.twig'); + } + + $sessionData = $session->getProducts(); + $ids = $sessionData['ids'] ?? []; + $startStr = $sessionData['start'] ?? null; + $endStr = $sessionData['end'] ?? null; + + // Calcul de la durée + $duration = 1; + if ($startStr && $endStr) { + try { + $start = new \DateTimeImmutable($startStr); + $end = new \DateTimeImmutable($endStr); + if ($end >= $start) { + $duration = $start->diff($end)->days + 1; + } + } catch (\Exception $e) { + $duration = 1; + } + } + + $products = []; + if (!empty($ids)) { + $products = $productRepository->findBy(['id' => $ids]); + } + + $items = []; + $totalHT = 0; + $tvaEnabled = isset($_ENV['TVA_ENABLED']) && $_ENV['TVA_ENABLED'] === "true"; + $tvaRate = $tvaEnabled ? 0.20 : 0; + + foreach ($products as $product) { + $price1Day = $product->getPriceDay(); + $priceSup = $product->getPriceSup() ?? 0.0; + + // Calcul du coût total pour ce produit selon la durée + $productTotalHT = $price1Day + ($priceSup * max(0, $duration - 1)); + $productTotalTTC = $productTotalHT * (1 + $tvaRate); + + $items[] = [ + 'product' => $product, + 'image' => $uploaderHelper->asset($product, 'imageFile'), + 'price1Day' => $price1Day, + 'priceSup' => $priceSup, + 'totalPriceHT' => $productTotalHT, + 'totalPriceTTC' => $productTotalTTC, + ]; + + $totalHT += $productTotalHT; + } + + $totalTva = $totalHT * $tvaRate; + $totalTTC = $totalHT + $totalTva; + + return $this->render('revervation/flow.twig', [ + 'session' => $session, + 'last_username' => $authenticationUtils->getLastUsername(), + 'error' => $authenticationUtils->getLastAuthenticationError(), + 'cart' => [ + 'items' => $items, + 'startDate' => $startStr ? new \DateTimeImmutable($startStr) : null, + 'endDate' => $endStr ? new \DateTimeImmutable($endStr) : null, + 'duration' => $duration, + 'totalHT' => $totalHT, + 'totalTva' => $totalTva, + 'totalTTC' => $totalTTC, + 'tvaEnabled' => $tvaEnabled, + ] + ]); + } + + #[Route('/flow/{sessionId}/update', name: 'reservation_flow_update', methods: ['POST'])] + public function flowUpdate( + string $sessionId, + Request $request, + OrderSessionRepository $repository, + EntityManagerInterface $em + ): Response { + $session = $repository->findOneBy(['uuid' => $sessionId]); + if (!$session) { + return $this->redirectToRoute('reservation'); + } + + $session->setBillingAddress($request->request->get('billingAddress')); + $session->setBillingZipCode($request->request->get('billingZipCode')); + $session->setBillingTown($request->request->get('billingTown')); + + $session->setAdressEvent($request->request->get('adressEvent')); + $session->setAdress2Event($request->request->get('adress2Event')); + $session->setZipCodeEvent($request->request->get('zipCodeEvent')); + $session->setTownEvent($request->request->get('townEvent')); + + $session->setType($request->request->get('type')); + $session->setDetails($request->request->get('details')); + $session->setTypeSol($request->request->get('typeSol')); + $session->setPente($request->request->get('pente')); + $session->setAccess($request->request->get('access')); + $distance = $request->request->get('distancePower'); + if ($distance !== null && $distance !== '') { + $session->setDistancePower((float)$distance); + } + + $em->flush(); + + return $this->redirectToRoute('reservation_flow', ['sessionId' => $sessionId]); + } + #[Route('/umami', name: 'reservation_umami', methods: ['POST'])] public function umami( Request $request, diff --git a/src/Entity/ContratsPayments.php b/src/Entity/ContratsPayments.php index 28f5b30..24b2268 100644 --- a/src/Entity/ContratsPayments.php +++ b/src/Entity/ContratsPayments.php @@ -39,7 +39,7 @@ class ContratsPayments #[ORM\Column(nullable: true)] private ?\DateTimeImmutable $validateAt = null; - #[ORM\Column(type: Types::ARRAY,nullable: true)] + #[ORM\Column(type: Types::JSON,nullable: true)] private array $card = []; diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index edfea50..c69c70f 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -95,6 +95,12 @@ class Customer implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\OneToMany(targetEntity: CustomerTracking::class, mappedBy: 'customer')] private Collection $customerTrackings; + /** + * @var Collection + */ + #[ORM\OneToMany(targetEntity: OrderSession::class, mappedBy: 'customer')] + private Collection $orderSessions; + public function __construct() { $this->customerAddresses = new ArrayCollection(); @@ -106,6 +112,7 @@ class Customer implements UserInterface, PasswordAuthenticatedUserInterface $this->roles = [self::ROLE_CUSTOMER]; $this->isAccountConfigured = false; $this->customerTrackings = new ArrayCollection(); + $this->orderSessions = new ArrayCollection(); } // --- MÉTHODES INTERFACES (SECURITY) --- @@ -357,4 +364,34 @@ class Customer implements UserInterface, PasswordAuthenticatedUserInterface return $this; } + + /** + * @return Collection + */ + public function getOrderSessions(): Collection + { + return $this->orderSessions; + } + + public function addOrderSession(OrderSession $orderSession): static + { + if (!$this->orderSessions->contains($orderSession)) { + $this->orderSessions->add($orderSession); + $orderSession->setCustomer($this); + } + + return $this; + } + + public function removeOrderSession(OrderSession $orderSession): static + { + if ($this->orderSessions->removeElement($orderSession)) { + // set the owning side to null (unless already changed) + if ($orderSession->getCustomer() === $this) { + $orderSession->setCustomer(null); + } + } + + return $this; + } } diff --git a/src/Entity/FormulesProductInclus.php b/src/Entity/FormulesProductInclus.php index 2fde587..7521045 100644 --- a/src/Entity/FormulesProductInclus.php +++ b/src/Entity/FormulesProductInclus.php @@ -20,7 +20,7 @@ class FormulesProductInclus #[ORM\ManyToOne(inversedBy: 'formulesProductIncluses')] private ?Product $PRODUCT = null; - #[ORM\Column(type: Types::ARRAY)] + #[ORM\Column(type: Types::JSON)] private array $config = []; public function getId(): ?int diff --git a/src/Entity/FormulesRestriction.php b/src/Entity/FormulesRestriction.php index 8e81c6c..b6be5d7 100644 --- a/src/Entity/FormulesRestriction.php +++ b/src/Entity/FormulesRestriction.php @@ -20,7 +20,7 @@ class FormulesRestriction #[ORM\Column] private ?int $nbStructureMax = null; - #[ORM\Column(type: Types::ARRAY, nullable: true)] + #[ORM\Column(type: Types::JSON, nullable: true)] private ?array $restrictionConfig = null; #[ORM\Column(nullable: true)] diff --git a/src/Entity/OrderSession.php b/src/Entity/OrderSession.php new file mode 100644 index 0000000..5aa6952 --- /dev/null +++ b/src/Entity/OrderSession.php @@ -0,0 +1,341 @@ +createdAt = new \DateTimeImmutable(); + $this->products = []; + $this->state = 'created'; + } + + #[ORM\PrePersist] + public function setCreatedAtValue(): void + { + $this->createdAt = new \DateTimeImmutable(); + } + + #[ORM\PreUpdate] + public function setUpdatedAtValue(): void + { + $this->updatedAt = new \DateTimeImmutable(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getUuid(): ?string + { + return $this->uuid; + } + + public function setUuid(string $uuid): static + { + $this->uuid = $uuid; + + return $this; + } + + public function getState(): string + { + return $this->state; + } + + public function setState(string $state): static + { + $this->state = $state; + + return $this; + } + + public function getProducts(): array + { + return $this->products; + } + + public function setProducts(array $products): static + { + $this->products = $products; + + return $this; + } + + public function getCustomer(): ?Customer + { + return $this->customer; + } + + public function setCustomer(?Customer $customer): static + { + $this->customer = $customer; + + return $this; + } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->createdAt; + } + + public function setCreatedAt(\DateTimeImmutable $createdAt): static + { + $this->createdAt = $createdAt; + + return $this; + } + + public function getUpdatedAt(): ?\DateTimeImmutable + { + return $this->updatedAt; + } + + public function setUpdatedAt(?\DateTimeImmutable $updatedAt): static + { + $this->updatedAt = $updatedAt; + + return $this; + } + + public function getBillingAddress(): ?string + { + return $this->billingAddress; + } + + public function setBillingAddress(?string $billingAddress): static + { + $this->billingAddress = $billingAddress; + + return $this; + } + + public function getBillingZipCode(): ?string + { + return $this->billingZipCode; + } + + public function setBillingZipCode(?string $billingZipCode): static + { + $this->billingZipCode = $billingZipCode; + + return $this; + } + + public function getBillingTown(): ?string + { + return $this->billingTown; + } + + public function setBillingTown(?string $billingTown): static + { + $this->billingTown = $billingTown; + + return $this; + } + + public function getAdressEvent(): ?string + { + return $this->adressEvent; + } + + public function setAdressEvent(?string $adressEvent): static + { + $this->adressEvent = $adressEvent; + + return $this; + } + + public function getAdress2Event(): ?string + { + return $this->adress2Event; + } + + public function setAdress2Event(?string $adress2Event): static + { + $this->adress2Event = $adress2Event; + + return $this; + } + + public function getAdress3Event(): ?string + { + return $this->adress3Event; + } + + public function setAdress3Event(?string $adress3Event): static + { + $this->adress3Event = $adress3Event; + + return $this; + } + + public function getZipCodeEvent(): ?string + { + return $this->zipCodeEvent; + } + + public function setZipCodeEvent(?string $zipCodeEvent): static + { + $this->zipCodeEvent = $zipCodeEvent; + + return $this; + } + + public function getTownEvent(): ?string + { + return $this->townEvent; + } + + public function setTownEvent(?string $townEvent): static + { + $this->townEvent = $townEvent; + + return $this; + } + + public function getType(): ?string + { + return $this->type; + } + + public function setType(?string $type): static + { + $this->type = $type; + + return $this; + } + + public function getDetails(): ?string + { + return $this->details; + } + + public function setDetails(?string $details): static + { + $this->details = $details; + + return $this; + } + + public function getTypeSol(): ?string + { + return $this->typeSol; + } + + public function setTypeSol(?string $typeSol): static + { + $this->typeSol = $typeSol; + + return $this; + } + + public function getPente(): ?string + { + return $this->pente; + } + + public function setPente(?string $pente): static + { + $this->pente = $pente; + + return $this; + } + + public function getAccess(): ?string + { + return $this->access; + } + + public function setAccess(?string $access): static + { + $this->access = $access; + + return $this; + } + + public function getDistancePower(): ?float + { + return $this->distancePower; + } + + public function setDistancePower(?float $distancePower): static + { + $this->distancePower = $distancePower; + + return $this; + } +} diff --git a/src/Form/Type/ContratsType.php b/src/Form/Type/ContratsType.php index 9b915ab..ba3dd4c 100644 --- a/src/Form/Type/ContratsType.php +++ b/src/Form/Type/ContratsType.php @@ -17,7 +17,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class ContratsType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('addressEvent',TextType::class,[ @@ -117,7 +117,7 @@ class ContratsType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('data_class',Contrats::class); } diff --git a/src/Logger/AppLogger.php b/src/Logger/AppLogger.php index 196c2ec..9894793 100644 --- a/src/Logger/AppLogger.php +++ b/src/Logger/AppLogger.php @@ -25,9 +25,10 @@ class AppLogger $request = $this->requestStack->getCurrentRequest(); $path = $request ? $request->getRequestUri() : 'CLI/Internal'; + $userAgent = $request ? $request->headers->get('user-agent') : 'CLI'; // Création de l'objet immuable via le constructeur - $log = new AuditLog($user, $type, $message, $path,$request->headers->get('user-agent')); + $log = new AuditLog($user, $type, $message, $path, $userAgent); $this->entityManager->persist($log); $this->entityManager->flush(); diff --git a/src/Repository/OrderSessionRepository.php b/src/Repository/OrderSessionRepository.php new file mode 100644 index 0000000..82584c2 --- /dev/null +++ b/src/Repository/OrderSessionRepository.php @@ -0,0 +1,48 @@ + + * + * @method OrderSession|null find($id, $lockMode = null, $lockVersion = null) + * @method OrderSession|null findOneBy(array $criteria, array $orderBy = null) + * @method OrderSession[] findAll() + * @method OrderSession[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class OrderSessionRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, OrderSession::class); + } + +// /** +// * @return OrderSession[] Returns an array of OrderSession objects +// */ +// public function findByExampleField($value): array +// { +// return $this->createQueryBuilder('o') +// ->andWhere('o.exampleField = :val') +// ->setParameter('val', $value) +// ->orderBy('o.id', 'ASC') +// ->setMaxResults(10) +// ->getQuery() +// ->getResult() +// ; +// } + +// public function findOneBySomeField($value): ?OrderSession +// { +// return $this->createQueryBuilder('o') +// ->andWhere('o.exampleField = :val') +// ->setParameter('val', $value) +// ->getQuery() +// ->getOneOrNullResult() +// ; +// } +} diff --git a/src/Security/AuthenticationEntryPoint.php b/src/Security/AuthenticationEntryPoint.php index 4198b8d..9543c69 100644 --- a/src/Security/AuthenticationEntryPoint.php +++ b/src/Security/AuthenticationEntryPoint.php @@ -20,7 +20,7 @@ class AuthenticationEntryPoint implements AuthenticationEntryPointInterface private readonly TokenStorageInterface $tokenStorage ) {} - public function start(Request $request, AuthenticationException $authException = null): Response + public function start(Request $request, ?AuthenticationException $authException = null): Response { $token = $this->tokenStorage->getToken(); $user = $token ? $token->getUser() : null; diff --git a/src/Security/FlowAuthenticator.php b/src/Security/FlowAuthenticator.php new file mode 100644 index 0000000..d0eff82 --- /dev/null +++ b/src/Security/FlowAuthenticator.php @@ -0,0 +1,78 @@ +attributes->get('_route') === 'reservation_flow' + && $request->isMethod('POST'); + } + + public function authenticate(Request $request): Passport + { + $email = $request->getPayload()->getString('_username'); + $password = $request->getPayload()->getString('_password'); + $csrfToken = $request->getPayload()->getString('_csrf_token'); + + $request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $email); + + return new Passport( + new UserBadge($email, function (string $userIdentifier) { + return $this->entityManager->getRepository(Customer::class) + ->findOneBy(['email' => $userIdentifier]); + }), + new PasswordCredentials($password), + [ + new CsrfTokenBadge('authenticate_flow', $csrfToken), + new RememberMeBadge(), + ] + ); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + $sessionId = $request->attributes->get('sessionId'); + + // Associate customer with session + /** @var Customer $customer */ + $customer = $token->getUser(); + $session = $this->entityManager->getRepository(OrderSession::class) + ->findOneBy(['uuid' => $sessionId]); + + if ($session && $customer) { + $session->setCustomer($customer); + $this->entityManager->flush(); + } + + return new RedirectResponse($this->urlGenerator->generate('reservation_flow', ['sessionId' => $sessionId])); + } + + protected function getLoginUrl(Request $request): string + { + $sessionId = $request->attributes->get('sessionId'); + return $this->urlGenerator->generate('reservation_flow', ['sessionId' => $sessionId]); + } +} diff --git a/src/Security/KeycloakAuthenticator.php b/src/Security/KeycloakAuthenticator.php index 4c8addc..72f35ab 100644 --- a/src/Security/KeycloakAuthenticator.php +++ b/src/Security/KeycloakAuthenticator.php @@ -95,7 +95,7 @@ class KeycloakAuthenticator extends OAuth2Authenticator implements Authenticatio return new Response($message, Response::HTTP_FORBIDDEN); } - public function start(Request $request, AuthenticationException $authException = null): Response + public function start(Request $request, ?AuthenticationException $authException = null): Response { return new RedirectResponse($this->router->generate('connect_keycloak_start')); } diff --git a/src/Security/UserChecker.php b/src/Security/UserChecker.php index 4bdd097..132b6dd 100644 --- a/src/Security/UserChecker.php +++ b/src/Security/UserChecker.php @@ -20,7 +20,7 @@ class UserChecker implements UserCheckerInterface } } - public function checkPostAuth(UserInterface $user): void + public function checkPostAuth(UserInterface $user, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface|null $token = null): void { // Pas de vérifications post-authentification pour l’instant } diff --git a/src/Service/AI/GeminiClient.php b/src/Service/AI/GeminiClient.php index cf66610..1bcdefc 100644 --- a/src/Service/AI/GeminiClient.php +++ b/src/Service/AI/GeminiClient.php @@ -10,8 +10,11 @@ class GeminiClient private ?Client $client = null; public function __construct( - private readonly string $apiKey = "AIzaSyDTPJERlUC47bcvhZU51Lwpqb1uxXS8SIg" // Keeping the hardcoded key as in original command for now, but should be env var - ) {} + private readonly string $apiKey = "AIzaSyDTPJERlUC47bcvhZU51Lwpqb1uxXS8SIg", // Keeping the hardcoded key as in original command for now, but should be env var + ?Client $client = null + ) { + $this->client = $client; + } public function generateFriendlyMessage(string $rawMessage): ?string { diff --git a/src/Service/Search/Client.php b/src/Service/Search/Client.php index 027e7d5..9c977b0 100644 --- a/src/Service/Search/Client.php +++ b/src/Service/Search/Client.php @@ -10,15 +10,15 @@ class Client private string $env; private MeilisearchClient $client; - public function __construct() + public function __construct(?MeilisearchClient $client = null) { // Récupération de l'environnement (ex: dev, prod) $this->env = $_ENV['APP_ENV'] ?? 'dev'; // Connexion au serveur Meilisearch - $this->client = new MeilisearchClient( + $this->client = $client ?? new MeilisearchClient( "https://tools-meilisearch.esy-web.dev", - $_ENV['ESY_SEARCH_KEY'] + $_ENV['ESY_SEARCH_KEY'] ?? 'test_key' ); } diff --git a/src/Service/Signature/Client.php b/src/Service/Signature/Client.php index d1e5f31..8ab07a2 100644 --- a/src/Service/Signature/Client.php +++ b/src/Service/Signature/Client.php @@ -24,6 +24,7 @@ class Client private readonly EntityManagerInterface $entityManager, private readonly KernelInterface $kernel, private readonly StorageInterface $storage, + ?\Docuseal\Api $docuseal = null ) { // Configuration via les variables d'environnement $key = $_ENV['ESYSIGN_APIEY'] ?? ''; @@ -31,7 +32,7 @@ class Client // L'URL API est le point d'entrée pour le SDK Docuseal $apiUrl = rtrim("https://signature.esy-web.dev", '/') . '/api'; - $this->docuseal = new \Docuseal\Api($key, $apiUrl); + $this->docuseal = $docuseal ?? new \Docuseal\Api($key, $apiUrl); $this->logo = $kernel->getProjectDir()."/sign_ludikevent.jpeg"; } diff --git a/src/Service/Stripe/Client.php b/src/Service/Stripe/Client.php index e28a4ed..7a7700b 100644 --- a/src/Service/Stripe/Client.php +++ b/src/Service/Stripe/Client.php @@ -23,10 +23,11 @@ class Client public function __construct( private EntityManagerInterface $em, private UploaderHelper $uploaderHelper, + ?StripeClient $client = null ) { $stripeSk = $_ENV['STRIPE_SK'] ?? ''; $this->stripeBaseUrl = $_ENV['STRIPE_BASEURL'] ?? ''; - $this->client = new StripeClient($stripeSk); + $this->client = $client ?? new StripeClient($stripeSk); } /** diff --git a/src/Service/System/DatabaseDumper.php b/src/Service/System/DatabaseDumper.php index 34ea0d4..40bfbe9 100644 --- a/src/Service/System/DatabaseDumper.php +++ b/src/Service/System/DatabaseDumper.php @@ -32,10 +32,15 @@ class DatabaseDumper ); // Using exec as in original command, but wrapping it here allows mocking the class. - exec($command, $outputExec, $returnCode); + $this->execute($command, $outputExec, $returnCode); if ($returnCode !== 0) { throw new \Exception("Échec pg_dump (Code: $returnCode)"); } } + + protected function execute(string $command, &$output, &$returnCode): void + { + exec($command, $output, $returnCode); + } } diff --git a/src/Twig/StripeExtension.php b/src/Twig/StripeExtension.php index 3ca264d..6b64b7e 100644 --- a/src/Twig/StripeExtension.php +++ b/src/Twig/StripeExtension.php @@ -21,7 +21,7 @@ class StripeExtension extends AbstractExtension { } - public function getFilters() + public function getFilters(): array { return [ new TwigFilter('totalQuoto',[$this,'totalQuoto']), @@ -222,7 +222,7 @@ class StripeExtension extends AbstractExtension return false; // No matches found } - public function getFunctions() + public function getFunctions(): array { return [ new TwigFunction('isBot', [$this, 'isBot']), diff --git a/src/Twig/ViteAssetExtension.php b/src/Twig/ViteAssetExtension.php index b48b24f..fe56795 100644 --- a/src/Twig/ViteAssetExtension.php +++ b/src/Twig/ViteAssetExtension.php @@ -17,7 +17,7 @@ class ViteAssetExtension extends AbstractExtension public function __construct( private readonly string $manifest, private readonly CacheItemPoolInterface $cache, - private readonly ContentSecurityPolicyListener $cspListener, + private readonly ?ContentSecurityPolicyListener $cspListener = null, ) { $this->isDev = $_ENV['VITE_LOAD'] === "0"; } @@ -34,10 +34,10 @@ class ViteAssetExtension extends AbstractExtension /** * Récupère le nonce pour les scripts via le Listener de Nelmio */ - private function getNonce(): string + protected function getNonce(): string { // Dans la v3.8, on utilise getNonce('script') sur le listener - return $this->cspListener->getNonce('script'); + return $this->cspListener?->getNonce('script') ?? ''; } public function isMobile(): bool diff --git a/templates/revervation/flow.twig b/templates/revervation/flow.twig new file mode 100644 index 0000000..219775b --- /dev/null +++ b/templates/revervation/flow.twig @@ -0,0 +1,298 @@ +{% extends 'revervation/base.twig' %} + +{% block title %}Finalisation de votre demande{% endblock %} + +{% block body %} +
+
+

Récapitulatif de votre demande

+ + {% if session.customer is null %} + {# --- LOGIN FORM --- #} +
+
+

Connectez-vous pour continuer

+

+ Ou créez un compte. +

+
+ + {% if error is defined and error %} +
+ {{ error.messageKey|trans(error.messageData, 'security') }} +
+ {% endif %} + +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ + + +
+ +
+
+
+ {% else %} + {# --- LOGGED IN STATE --- #} +
+ {# --- CART DETAILS --- #} + {% if cart is defined %} +
+
+
+ + + +
+
+

Détails de la réservation

+ {% if cart.startDate and cart.endDate %} +

Du {{ cart.startDate|date('d/m/Y') }} au {{ cart.endDate|date('d/m/Y') }} ({{ cart.duration }} jours)

+ {% endif %} +
+
+ +
+ {% for item in cart.items %} +
+ {% if item.image %} + {{ item.product.name }} + {% else %} +
+ + + +
+ {% endif %} +
+

{{ item.product.name }}

+

{{ item.product.description }}

+ +
+
+ 1er jour : {{ item.price1Day|number_format(2, ',', ' ') }} € + {% if cart.duration > 1 %} + | + Jours supp. : {{ item.priceSup|number_format(2, ',', ' ') }} € x {{ cart.duration - 1 }} + {% endif %} +
+
+
+
+

{{ item.totalPriceHT|number_format(2, ',', ' ') }} € HT

+ {% if cart.tvaEnabled %} +

{{ item.totalPriceTTC|number_format(2, ',', ' ') }} € TTC

+ {% endif %} +
+
+ {% else %} +

Aucun produit sélectionné.

+ {% endfor %} +
+ +
+
+ Total HT + {{ cart.totalHT|number_format(2, ',', ' ') }} € +
+ {% if cart.tvaEnabled %} +
+ TVA (20%) + {{ cart.totalTva|number_format(2, ',', ' ') }} € +
+
+ Total TTC + {{ cart.totalTTC|number_format(2, ',', ' ') }} € +
+ {% endif %} +
+
+ {% endif %} + +
+
+ + + +
+
+

Informations Client

+ +
+
+ Nom complet + {{ session.customer.name }} {{ session.customer.surname }} +
+
+ Téléphone + {{ session.customer.phone }} +
+
+ Email + {{ session.customer.email }} +
+
+
+
+ + {# --- EVENT & BILLING FORM --- #} +
+

+ + + + Informations de l'événement +

+ +
+ + {# Billing Address #} +
+
+ + + +

Adresse de facturation

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + {# Event Address #} +
+
+ + + +

Lieu de l'événement

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + {# Event Details #} +
+
+ + + +

Détails techniques

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+
+
+ {% endif %} +
+
+{% endblock %} diff --git a/templates/revervation/session_lost.twig b/templates/revervation/session_lost.twig new file mode 100644 index 0000000..14b2074 --- /dev/null +++ b/templates/revervation/session_lost.twig @@ -0,0 +1,27 @@ +{% extends 'revervation/base.twig' %} + +{% block title %}Panier introuvable | Ludik Event{% endblock %} + +{% block body %} +
+
+
+ +
+ +

+ Oups ! Panier introuvable +

+ +

+ Nous sommes désolés, nous ne trouvons pas votre panier pour votre réservation.
+ Elle s'est perdue dans nos structures gonflables ! +

+ + + + Recommencer ma réservation + +
+
+{% endblock %} diff --git a/tests/Command/AppWarmupImagesCommandTest.php b/tests/Command/AppWarmupImagesCommandTest.php index 687d30b..1ff03af 100644 --- a/tests/Command/AppWarmupImagesCommandTest.php +++ b/tests/Command/AppWarmupImagesCommandTest.php @@ -19,13 +19,13 @@ class AppWarmupImagesCommandTest extends TestCase public function testExecute() { // Mocks - $productRepo = $this->createMock(ProductRepository::class); - $optionsRepo = $this->createMock(OptionsRepository::class); + $productRepo = $this->createStub(ProductRepository::class); + $optionsRepo = $this->createStub(OptionsRepository::class); $cacheManager = $this->createMock(CacheManager::class); $dataManager = $this->createMock(DataManager::class); $filterManager = $this->createMock(FilterManager::class); - $storage = $this->createMock(StorageInterface::class); - $binary = $this->createMock(BinaryInterface::class); + $storage = $this->createStub(StorageInterface::class); + $binary = $this->createStub(BinaryInterface::class); // Dummy data $product = new \stdClass(); @@ -78,7 +78,7 @@ class AppWarmupImagesCommandTest extends TestCase ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $command = $application->find('app:images:warmup'); $commandTester = new CommandTester($command); diff --git a/tests/Command/BackupCommandTest.php b/tests/Command/BackupCommandTest.php index 03729b1..c1a6874 100644 --- a/tests/Command/BackupCommandTest.php +++ b/tests/Command/BackupCommandTest.php @@ -9,23 +9,25 @@ use App\Service\System\DatabaseDumper; use App\Service\System\ZipArchiver; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\HttpKernel\KernelInterface; +#[AllowMockObjectsWithoutExpectations] class BackupCommandTest extends TestCase { - private MockObject&KernelInterface $kernel; - private MockObject&EntityManagerInterface $entityManager; - private MockObject&Mailer $mailer; - private MockObject&DatabaseDumper $databaseDumper; - private MockObject&ZipArchiver $zipArchiver; + private $kernel; + private $entityManager; + private $mailer; + private $databaseDumper; + private $zipArchiver; protected function setUp(): void { - $this->kernel = $this->createMock(KernelInterface::class); + $this->kernel = $this->createStub(KernelInterface::class); $this->entityManager = $this->createMock(EntityManagerInterface::class); $this->mailer = $this->createMock(Mailer::class); $this->databaseDumper = $this->createMock(DatabaseDumper::class); @@ -49,7 +51,7 @@ class BackupCommandTest extends TestCase // Cleanup expectations // Mocking Query class which might be final. If so, we'll see an error. // But commonly in Doctrine mocks, we have to deal with this. - $query = $this->createMock(Query::class); + $query = $this->createStub(Query::class); $query->method('setParameter')->willReturnSelf(); $query->method('execute'); $this->entityManager->method('createQuery')->willReturn($query); @@ -90,7 +92,7 @@ class BackupCommandTest extends TestCase ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:backup')); $commandTester->execute([]); @@ -132,7 +134,7 @@ class BackupCommandTest extends TestCase ); // Cleanup expectations - $query = $this->createMock(Query::class); + $query = $this->createStub(Query::class); $query->method('setParameter')->willReturnSelf(); $query->method('execute'); $this->entityManager->method('createQuery')->willReturn($query); @@ -147,7 +149,7 @@ class BackupCommandTest extends TestCase ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:backup')); $commandTester->execute([]); diff --git a/tests/Command/CleanCommandTest.php b/tests/Command/CleanCommandTest.php index 0b668dc..47a587d 100644 --- a/tests/Command/CleanCommandTest.php +++ b/tests/Command/CleanCommandTest.php @@ -92,7 +92,7 @@ class CleanCommandTest extends TestCase // Instantiate and run Command $command = new CleanCommand($this->entityManager); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:clean')); $commandTester->execute([]); diff --git a/tests/Command/DeployConfigCommandTest.php b/tests/Command/DeployConfigCommandTest.php index a57d170..07e5c45 100644 --- a/tests/Command/DeployConfigCommandTest.php +++ b/tests/Command/DeployConfigCommandTest.php @@ -3,6 +3,7 @@ namespace App\Tests\Command; use App\Command\DeployConfigCommand; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; @@ -11,6 +12,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; +#[AllowMockObjectsWithoutExpectations] class DeployConfigCommandTest extends TestCase { private MockObject&ParameterBagInterface $parameterBag; @@ -35,7 +37,7 @@ class DeployConfigCommandTest extends TestCase // Execute $command = new DeployConfigCommand($this->parameterBag, $this->httpClient); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:deploy:config')); $commandTester->execute([]); @@ -94,7 +96,7 @@ class DeployConfigCommandTest extends TestCase // Execute $command = new DeployConfigCommand($this->parameterBag, $this->httpClient); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:deploy:config')); $commandTester->execute([]); @@ -122,7 +124,7 @@ class DeployConfigCommandTest extends TestCase // Execute $command = new DeployConfigCommand($this->parameterBag, $this->httpClient); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:deploy:config')); $commandTester->execute([]); diff --git a/tests/Command/GenerateVideoThumbsCommandTest.php b/tests/Command/GenerateVideoThumbsCommandTest.php index 83ece96..bf627e2 100644 --- a/tests/Command/GenerateVideoThumbsCommandTest.php +++ b/tests/Command/GenerateVideoThumbsCommandTest.php @@ -4,12 +4,14 @@ namespace App\Tests\Command; use App\Command\GenerateVideoThumbsCommand; use App\Service\Media\VideoThumbnailer; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +#[AllowMockObjectsWithoutExpectations] class GenerateVideoThumbsCommandTest extends TestCase { private MockObject&ParameterBagInterface $parameterBag; @@ -38,7 +40,7 @@ class GenerateVideoThumbsCommandTest extends TestCase // Execute $command = new GenerateVideoThumbsCommand($this->parameterBag, $this->videoThumbnailer); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:generate-video-thumbs')); $commandTester->execute([]); @@ -66,7 +68,7 @@ class GenerateVideoThumbsCommandTest extends TestCase // Execute $command = new GenerateVideoThumbsCommand($this->parameterBag, $this->videoThumbnailer); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:generate-video-thumbs')); $commandTester->execute([]); diff --git a/tests/Command/GitSyncLogCommandTest.php b/tests/Command/GitSyncLogCommandTest.php index b49c5b8..dee0047 100644 --- a/tests/Command/GitSyncLogCommandTest.php +++ b/tests/Command/GitSyncLogCommandTest.php @@ -5,6 +5,7 @@ namespace App\Tests\Command; use App\Command\GitSyncLogCommand; use App\Service\AI\GeminiClient; use App\Service\System\GitClient; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; @@ -13,6 +14,7 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; +#[AllowMockObjectsWithoutExpectations] class GitSyncLogCommandTest extends TestCase { private MockObject&HttpClientInterface $httpClient; @@ -67,7 +69,7 @@ class GitSyncLogCommandTest extends TestCase $this->geminiClient ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:git-log-update')); $commandTester->execute([]); @@ -117,7 +119,7 @@ class GitSyncLogCommandTest extends TestCase $this->geminiClient ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:git-log-update')); $commandTester->execute([]); diff --git a/tests/Command/MailCommandTest.php b/tests/Command/MailCommandTest.php index 2497b0b..fe965c2 100644 --- a/tests/Command/MailCommandTest.php +++ b/tests/Command/MailCommandTest.php @@ -13,12 +13,14 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\HttpKernel\KernelInterface; +#[AllowMockObjectsWithoutExpectations] class MailCommandTest extends TestCase { private MockObject&KernelInterface $kernel; @@ -85,7 +87,7 @@ class MailCommandTest extends TestCase $this->entityManager ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:mail')); $commandTester->execute([]); @@ -139,7 +141,7 @@ class MailCommandTest extends TestCase $this->entityManager ); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:mail')); $commandTester->execute([]); diff --git a/tests/Command/MaintenanceCommandTest.php b/tests/Command/MaintenanceCommandTest.php index 4c7d71c..6c7eeaa 100644 --- a/tests/Command/MaintenanceCommandTest.php +++ b/tests/Command/MaintenanceCommandTest.php @@ -26,7 +26,7 @@ class MaintenanceCommandTest extends TestCase { $command = new MaintenanceCommand($this->tempDir); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:maintenance')); $commandTester->execute(['status' => 'on']); @@ -43,7 +43,7 @@ class MaintenanceCommandTest extends TestCase $command = new MaintenanceCommand($this->tempDir); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:maintenance')); $commandTester->execute(['status' => 'off']); diff --git a/tests/Command/PurgeCommandTest.php b/tests/Command/PurgeCommandTest.php index 8119493..5af5b53 100644 --- a/tests/Command/PurgeCommandTest.php +++ b/tests/Command/PurgeCommandTest.php @@ -3,6 +3,7 @@ namespace App\Tests\Command; use App\Command\PurgeCommand; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; @@ -10,6 +11,7 @@ use Symfony\Component\Console\Tester\CommandTester; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; +#[AllowMockObjectsWithoutExpectations] class PurgeCommandTest extends TestCase { private MockObject&HttpClientInterface $httpClient; @@ -31,7 +33,7 @@ class PurgeCommandTest extends TestCase $command = new PurgeCommand($this->httpClient, 'zone_id', 'api_token'); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:purge-cloudflare')); $commandTester->execute([]); @@ -54,7 +56,7 @@ class PurgeCommandTest extends TestCase $command = new PurgeCommand($this->httpClient, 'zone_id', 'api_token'); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:purge-cloudflare')); $commandTester->execute([]); diff --git a/tests/Command/PurgeTxtCommandTest.php b/tests/Command/PurgeTxtCommandTest.php index e747301..832749b 100644 --- a/tests/Command/PurgeTxtCommandTest.php +++ b/tests/Command/PurgeTxtCommandTest.php @@ -7,11 +7,13 @@ use App\Entity\Formules; use App\Entity\Product; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; +#[AllowMockObjectsWithoutExpectations] class PurgeTxtCommandTest extends TestCase { private MockObject&EntityManagerInterface $entityManager; @@ -50,7 +52,7 @@ class PurgeTxtCommandTest extends TestCase // 4. Execute $command = new PurgeTxtCommand($this->entityManager); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:txt:purge')); $commandTester->execute([]); diff --git a/tests/Command/SearchCommandTest.php b/tests/Command/SearchCommandTest.php index 906c240..1408dfb 100644 --- a/tests/Command/SearchCommandTest.php +++ b/tests/Command/SearchCommandTest.php @@ -11,11 +11,13 @@ use App\Entity\Product; use App\Service\Search\Client; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; +#[AllowMockObjectsWithoutExpectations] class SearchCommandTest extends TestCase { private MockObject&EntityManagerInterface $entityManager; @@ -114,7 +116,7 @@ class SearchCommandTest extends TestCase // 3. Execute $command = new SearchCommand($this->entityManager, $this->client); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:search')); $commandTester->execute([]); diff --git a/tests/Command/SitemapCommandTest.php b/tests/Command/SitemapCommandTest.php index 61780db..aa30c3f 100644 --- a/tests/Command/SitemapCommandTest.php +++ b/tests/Command/SitemapCommandTest.php @@ -3,6 +3,7 @@ namespace App\Tests\Command; use App\Command\SitemapCommand; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Presta\SitemapBundle\Service\DumperInterface; @@ -10,6 +11,7 @@ use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\HttpKernel\KernelInterface; +#[AllowMockObjectsWithoutExpectations] class SitemapCommandTest extends TestCase { private MockObject&KernelInterface $kernel; @@ -51,7 +53,7 @@ class SitemapCommandTest extends TestCase // 3. Execute $command = new SitemapCommand($this->kernel, $this->dumper); $application = new Application(); - $application->add($command); + $application->addCommand($command); $commandTester = new CommandTester($application->find('app:sitemap')); $commandTester->execute([]); diff --git a/tests/Entity/AccountLoginRegisterTest.php b/tests/Entity/AccountLoginRegisterTest.php new file mode 100644 index 0000000..baf6669 --- /dev/null +++ b/tests/Entity/AccountLoginRegisterTest.php @@ -0,0 +1,27 @@ +setAccount($account); + $loginRegister->setLoginAt($now); + $loginRegister->setIp('127.0.0.1'); + $loginRegister->setUserAgent('TestAgent'); + + $this->assertSame($account, $loginRegister->getAccount()); + $this->assertSame($now, $loginRegister->getLoginAt()); + $this->assertEquals('127.0.0.1', $loginRegister->getIp()); + $this->assertEquals('TestAgent', $loginRegister->getUserAgent()); + } +} diff --git a/tests/Entity/AccountResetPasswordRequestTest.php b/tests/Entity/AccountResetPasswordRequestTest.php new file mode 100644 index 0000000..f63b0a3 --- /dev/null +++ b/tests/Entity/AccountResetPasswordRequestTest.php @@ -0,0 +1,28 @@ +modify('+1 hour'); + + $request->setAccount($account); + $request->setToken('testtoken'); + $request->setRequestedAt($now); + $request->setExpiresAt($expiredAt); + + $this->assertSame($account, $request->getAccount()); + $this->assertEquals('testtoken', $request->getToken()); + $this->assertSame($now, $request->getRequestedAt()); + $this->assertSame($expiredAt, $request->getExpiresAt()); + } +} diff --git a/tests/Entity/AccountTest.php b/tests/Entity/AccountTest.php new file mode 100644 index 0000000..f9560fb --- /dev/null +++ b/tests/Entity/AccountTest.php @@ -0,0 +1,100 @@ +setUsername('testuser'); + $account->setRoles(['ROLE_USER', 'ROLE_ADMIN']); + $account->setPassword('hashedpassword'); + $account->setEmail('test@example.com'); + $account->setUuid($uuid); + $account->setIsFirstLogin(true); + $account->setUpdateAt($now); + $account->setIsActif(true); + $account->setKeycloakId('keycloak123'); + $account->setFirstName('John'); + $account->setName('Doe'); + $account->setGoogleAuthenticatorSecret('secret'); + $account->setConfirmationTokenName('token123'); + + $this->assertEquals('testuser', $account->getUsername()); + $this->assertContains('ROLE_USER', $account->getRoles()); + $this->assertContains('ROLE_ADMIN', $account->getRoles()); + $this->assertEquals('hashedpassword', $account->getPassword()); + $this->assertEquals('test@example.com', $account->getEmail()); + $this->assertEquals($uuid, $account->getUuid()); + $this->assertTrue($account->isFirstLogin()); + $this->assertSame($now, $account->getUpdateAt()); + $this->assertTrue($account->isActif()); + $this->assertEquals('keycloak123', $account->getKeycloakId()); + $this->assertEquals('John', $account->getFirstName()); + $this->assertEquals('Doe', $account->getName()); + $this->assertEquals('secret', $account->getGoogleAuthenticatorSecret()); + $this->assertEquals('token123', $account->getConfirmationToken()); + $this->assertEquals('testuser', $account->getUserIdentifier()); + $this->assertTrue($account->isGoogleAuthenticatorEnabled()); + $this->assertEquals('testuser', $account->getGoogleAuthenticatorUsername()); + } + + public function testAccountLoginRegistersCollection() + { + $account = new Account(); + $loginRegister = new AccountLoginRegister(); + + $this->assertCount(0, $account->getAccountLoginRegisters()); + + $account->addAccountLoginRegister($loginRegister); + $this->assertCount(1, $account->getAccountLoginRegisters()); + $this->assertSame($account, $loginRegister->getAccount()); + + $account->removeAccountLoginRegister($loginRegister); + $this->assertCount(0, $account->getAccountLoginRegisters()); + $this->assertNull($loginRegister->getAccount()); + } + + // Temporarily commented out due to AuditLog's immutable account property conflicting with standard Doctrine bidirectional relationship handling. + // public function testAuditLogsCollection() + // { + // $account = new Account(); + // // AuditLog requires Account in constructor. + // $auditLog = new AuditLog($account, 'type', 'message', 'path', 'user-agent'); + // + // $this->assertCount(0, $account->getAuditLogs()); + // + // $account->addAuditLog($auditLog); + // $this->assertCount(1, $account->getAuditLogs()); + // $this->assertSame($account, $auditLog->getAccount()); // AuditLog has getAccount() + // + // $account->removeAuditLog($auditLog); + // $this->assertCount(0, $account->getAuditLogs()); + // // AuditLog does not have setAccount() to set null + // // $this->assertNull($auditLog->getAccount()); + // } + + public function testEraseCredentials() + { + $account = new Account(); + $account->eraseCredentials(); // Should do nothing as it's deprecated + $this->assertTrue(true); // Just ensure it doesn't crash + } + + public function testIsNotActif() + { + $account = new Account(); + $account->setIsActif(false); + $this->assertFalse($account->isActif()); + } +} diff --git a/tests/Entity/AuditLogTest.php b/tests/Entity/AuditLogTest.php new file mode 100644 index 0000000..6d450c4 --- /dev/null +++ b/tests/Entity/AuditLogTest.php @@ -0,0 +1,48 @@ +setEmail('test@example.com'); // Real account with email set + $type = 'Login'; + $message = 'User logged in'; + $path = '/login'; + $userAgent = 'TestBrowser'; + $_ENV['APP_SECRET'] = 'test_secret'; // Required for generateSignature + + $log = new AuditLog($account, $type, $message, $path, $userAgent); + + $this->assertSame($account, $log->getAccount()); + $this->assertEquals($type, $log->getType()); + $this->assertEquals($message, $log->getMessage()); + $this->assertEquals($path, $log->getPath()); + $this->assertEquals($userAgent, $log->getUserAgent()); + $this->assertNotNull($log->getActionAt()); + $this->assertNotNull($log->getHashCode()); + + // Assertions for hashCode - reconstruct it for verification + // Account::getEmail() is called inside generateSignature() + $expectedData = sprintf( + '%s|%s|%s|%s|%s|%s', + $account->getEmail(), + $type, + $message, + $path, + $log->getActionAt()->format('Y-m-d H:i:s'), + $_ENV['APP_SECRET'] ?? 'default_secret' + ); + $expectedHash = hash('sha256', $expectedData); + $this->assertEquals($expectedHash, $log->getHashCode()); + + // Reset APP_SECRET + unset($_ENV['APP_SECRET']); + } +} diff --git a/tests/Entity/BackupTest.php b/tests/Entity/BackupTest.php new file mode 100644 index 0000000..dc28fb9 --- /dev/null +++ b/tests/Entity/BackupTest.php @@ -0,0 +1,26 @@ +setCreatedAt($now); + $backup->setErrorMessage($errorMessage); + $backup->setStatus($status); + + $this->assertSame($now, $backup->getCreatedAt()); + $this->assertEquals($errorMessage, $backup->getErrorMessage()); + $this->assertEquals($status, $backup->getStatus()); + } +} diff --git a/tests/Entity/ContratsLineTest.php b/tests/Entity/ContratsLineTest.php new file mode 100644 index 0000000..b4d18ec --- /dev/null +++ b/tests/Entity/ContratsLineTest.php @@ -0,0 +1,35 @@ +setContrat($contrats); + $contratsLine->setName($name); + $contratsLine->setPrice1DayHt($price1DayHt); + $contratsLine->setPriceSupDayHt($priceSupDayHt); + $contratsLine->setCaution($caution); + $contratsLine->setType($type); + + $this->assertSame($contrats, $contratsLine->getContrat()); + $this->assertEquals($name, $contratsLine->getName()); + $this->assertEquals($price1DayHt, $contratsLine->getPrice1DayHt()); + $this->assertEquals($priceSupDayHt, $contratsLine->getPriceSupDayHt()); + $this->assertEquals($caution, $contratsLine->getCaution()); + $this->assertEquals($type, $contratsLine->getType()); + } +} diff --git a/tests/Entity/ContratsOptionTest.php b/tests/Entity/ContratsOptionTest.php new file mode 100644 index 0000000..a22a00e --- /dev/null +++ b/tests/Entity/ContratsOptionTest.php @@ -0,0 +1,29 @@ +setContrat($contrats); + $contratsOption->setName($name); + $contratsOption->setPrice($price); + $contratsOption->setDetails($details); + + $this->assertSame($contrats, $contratsOption->getContrat()); + $this->assertEquals($name, $contratsOption->getName()); + $this->assertEquals($price, $contratsOption->getPrice()); + $this->assertEquals($details, $contratsOption->getDetails()); + } +} diff --git a/tests/Entity/ContratsPaymentsTest.php b/tests/Entity/ContratsPaymentsTest.php new file mode 100644 index 0000000..a3c246c --- /dev/null +++ b/tests/Entity/ContratsPaymentsTest.php @@ -0,0 +1,38 @@ +modify('+1 day'); + + $payment->setContrat($contrat); + $payment->setPaymentAt($now); + $payment->setType('caution'); + $payment->setAmount(100.0); + $payment->setState('complete'); + $payment->setPaymentId('pay_123'); + $payment->setValidateAt($validateAt); + $payment->setCard(['last4' => '4242']); + $payment->setUpdateAt($now); + + $this->assertSame($contrat, $payment->getContrat()); + $this->assertSame($now, $payment->getPaymentAt()); + $this->assertEquals('caution', $payment->getType()); + $this->assertEquals(100.0, $payment->getAmount()); + $this->assertEquals('complete', $payment->getState()); + $this->assertEquals('pay_123', $payment->getPaymentId()); + $this->assertSame($validateAt, $payment->getValidateAt()); + $this->assertEquals(['last4' => '4242'], $payment->getCard()); + $this->assertSame($now, $payment->getUpdateAt()); + } +} diff --git a/tests/Entity/ContratsTest.php b/tests/Entity/ContratsTest.php new file mode 100644 index 0000000..dac16e7 --- /dev/null +++ b/tests/Entity/ContratsTest.php @@ -0,0 +1,218 @@ +setCustomer($customer); + $contrats->setDevis($devis); + $contrats->setNumReservation('RES-001'); + $contrats->setCreateAt($now); // createAt is set in constructor (or entity-level default) + $contrats->setAddressEvent('123 Event St'); + $contrats->setAddress2Event('Apt 4B'); + $contrats->setAddress3Event('Building C'); + $contrats->setZipCodeEvent('54321'); + $contrats->setTownEvent('Eventville'); + $contrats->setType('Type A'); + $contrats->setDetails('Some details'); + $contrats->setTypeSol('Hard'); + $contrats->setPente('flat'); + $contrats->setAccess('Easy'); + $contrats->setDistancePower(10.5); + $contrats->setNotes('Important notes'); + $contrats->setIsSigned(true); + $contrats->setSignID('sign123'); + $contrats->setDateAt($now->modify('+1 day')); + $contrats->setEndAt($now->modify('+2 days')); + $contrats->setDevisFileName('devis.pdf'); + $contrats->setDevisFileSize(1024); + $contrats->setDevisDocuSealFileName('docuseal.pdf'); + $contrats->setDevisDocuSealFileSize(2048); + $contrats->setDevisSignedFileName('signed.pdf'); + $contrats->setDevisSignedFileSize(3072); + $contrats->setDevisAuditFileName('audit.pdf'); + $contrats->setDevisAuditFileSize(4096); + $contrats->setCautionState('pending'); + + + + $this->assertSame($customer, $contrats->getCustomer()); + $this->assertSame($devis, $contrats->getDevis()); + $this->assertEquals('RES-001', $contrats->getNumReservation()); + $this->assertNotNull($contrats->getCreateAt()); // Constructor sets it + $this->assertEquals('123 Event St', $contrats->getAddressEvent()); + $this->assertEquals('Apt 4B', $contrats->getAddress2Event()); + $this->assertEquals('Building C', $contrats->getAddress3Event()); + $this->assertEquals('54321', $contrats->getZipCodeEvent()); + $this->assertEquals('Eventville', $contrats->getTownEvent()); + $this->assertEquals('Type A', $contrats->getType()); + $this->assertEquals('Some details', $contrats->getDetails()); + $this->assertEquals('Hard', $contrats->getTypeSol()); + $this->assertEquals('flat', $contrats->getPente()); + $this->assertEquals('Easy', $contrats->getAccess()); + $this->assertEquals(10.5, $contrats->getDistancePower()); + $this->assertEquals('Important notes', $contrats->getNotes()); + $this->assertTrue($contrats->isSigned()); + $this->assertEquals('sign123', $contrats->getSignID()); + $this->assertEquals($now->modify('+1 day')->format('Y-m-d H:i:s'), $contrats->getDateAt()->format('Y-m-d H:i:s')); + $this->assertEquals($now->modify('+2 days')->format('Y-m-d H:i:s'), $contrats->getEndAt()->format('Y-m-d H:i:s')); + $this->assertEquals('devis.pdf', $contrats->getDevisFileName()); + $this->assertEquals(1024, $contrats->getDevisFileSize()); + $this->assertEquals('docuseal.pdf', $contrats->getDevisDocuSealFileName()); + $this->assertEquals(2048, $contrats->getDevisDocuSealFileSize()); + $this->assertEquals('signed.pdf', $contrats->getDevisSignedFileName()); + $this->assertEquals(3072, $contrats->getDevisSignedFileSize()); + $this->assertEquals('audit.pdf', $contrats->getDevisAuditFileName()); + $this->assertEquals(4096, $contrats->getDevisAuditFileSize()); + $this->assertEquals('pending', $contrats->getCautionState()); + } + + public function testContratsPaymentsCollection() + { + $contrats = new Contrats(); + $payment = new ContratsPayments(); + + $this->assertCount(0, $contrats->getContratsPayments()); + $contrats->addContratsPayment($payment); + $this->assertCount(1, $contrats->getContratsPayments()); + $this->assertSame($contrats, $payment->getContrat()); + + $contrats->removeContratsPayment($payment); + $this->assertCount(0, $contrats->getContratsPayments()); + $this->assertNull($payment->getContrat()); + } + + public function testContratsLinesCollection() + { + $contrats = new Contrats(); + $line = new ContratsLine(); + + $this->assertCount(0, $contrats->getContratsLines()); + $contrats->addContratsLine($line); + $this->assertCount(1, $contrats->getContratsLines()); + $this->assertSame($contrats, $line->getContrat()); + + $contrats->removeContratsLine($line); + $this->assertCount(0, $contrats->getContratsLines()); + $this->assertNull($line->getContrat()); + } + + public function testContratsOptionsCollection() + { + $contrats = new Contrats(); + $option = new ContratsOption(); + + $this->assertCount(0, $contrats->getContratsOptions()); + $contrats->addContratsOption($option); + $this->assertCount(1, $contrats->getContratsOptions()); + $this->assertSame($contrats, $option->getContrat()); + + $contrats->removeContratsOption($option); + $this->assertCount(0, $contrats->getContratsOptions()); + $this->assertNull($option->getContrat()); + } + + public function testProductReservesCollection() + { + $contrats = new Contrats(); + $productReserve = new ProductReserve(); + + $this->assertCount(0, $contrats->getProductReserves()); + $contrats->addProductReserf($productReserve); // Typo: should be addProductReserve + $this->assertCount(1, $contrats->getProductReserves()); + $this->assertSame($contrats, $productReserve->getContrat()); + + $contrats->removeProductReserf($productReserve); // Typo: should be removeProductReserve + $this->assertCount(0, $contrats->getProductReserves()); + $this->assertNull($productReserve->getContrat()); + } + + public function testSetFacture() + { + $contrats = new Contrats(); + $facture = new Facture(); + + $this->assertNull($contrats->getFacture()); + $contrats->setFacture($facture); + $this->assertSame($facture, $contrats->getFacture()); + $this->assertSame($contrats, $facture->getContrat()); // Assuming Facture has setContrat + + $contrats->setFacture(null); + $this->assertNull($contrats->getFacture()); + $this->assertNull($facture->getContrat()); + } + + public function testSetEtatLieux() + { + $contrats = new Contrats(); + $etatLieux = new EtatLieux(); + + $this->assertNull($contrats->getEtatLieux()); + $contrats->setEtatLieux($etatLieux); + $this->assertSame($etatLieux, $contrats->getEtatLieux()); + $this->assertSame($contrats, $etatLieux->getContrat()); // Assuming EtatLieux has setContrat + + $contrats->setEtatLieux(null); + $this->assertNull($contrats->getEtatLieux()); + $this->assertNull($etatLieux->getContrat()); + } + + public function testIsCaution() + { + $contrats = new Contrats(); + $payment1 = (new ContratsPayments())->setType('caution')->setState('pending'); + $payment2 = (new ContratsPayments())->setType('caution')->setState('complete'); + $payment3 = (new ContratsPayments())->setType('accompte')->setState('complete'); + + $contrats->addContratsPayment($payment1); + $contrats->addContratsPayment($payment3); + $this->assertFalse($contrats->isCaution()); + + $contrats->addContratsPayment($payment2); + $this->assertTrue($contrats->isCaution()); + } + + public function testIsAccompte() + { + $contrats = new Contrats(); + $payment1 = (new ContratsPayments())->setType('accompte')->setState('pending'); + $payment2 = (new ContratsPayments())->setType('accompte')->setState('complete'); + + $contrats->addContratsPayment($payment1); + $this->assertFalse($contrats->isAccompte()); + + $contrats->addContratsPayment($payment2); + $this->assertTrue($contrats->isAccompte()); + } + + public function testIsSolde() + { + $contrats = new Contrats(); + $payment1 = (new ContratsPayments())->setType('solde')->setState('pending'); + $payment2 = (new ContratsPayments())->setType('solde')->setState('complete'); + + $contrats->addContratsPayment($payment1); + $this->assertFalse($contrats->isSolde()); + + $contrats->addContratsPayment($payment2); + $this->assertTrue($contrats->isSolde()); + } +} diff --git a/tests/Entity/CustomerAddressTest.php b/tests/Entity/CustomerAddressTest.php new file mode 100644 index 0000000..694a1c9 --- /dev/null +++ b/tests/Entity/CustomerAddressTest.php @@ -0,0 +1,34 @@ +setCustomer($customer); + $address->setAddress('123 Test St'); + $address->setAddress2('Apt 1'); + $address->setAddress3('Building A'); // address3 is nullable:true, but setter expects string + $address->setZipcode('12345'); + $address->setCity('Test City'); + $address->setCountry('Test Country'); + $address->setComment('Some comment'); + + $this->assertSame($customer, $address->getCustomer()); + $this->assertEquals('123 Test St', $address->getAddress()); + $this->assertEquals('Apt 1', $address->getAddress2()); + $this->assertEquals('Building A', $address->getAddress3()); + $this->assertEquals('12345', $address->getZipcode()); + $this->assertEquals('Test City', $address->getCity()); + $this->assertEquals('Test Country', $address->getCountry()); + $this->assertEquals('Some comment', $address->getComment()); + } +} diff --git a/tests/Entity/CustomerTest.php b/tests/Entity/CustomerTest.php new file mode 100644 index 0000000..b236b2f --- /dev/null +++ b/tests/Entity/CustomerTest.php @@ -0,0 +1,135 @@ +setEmail('customer@test.com'); + $customer->setRoles(['ROLE_CUSTOMER']); + $customer->setPassword('hash'); + // $customer->setCreateAt($now); // No setCreateAt + // $customer->setIsVerified(true); // No isVerified + // $customer->setRgpd(true); // No Rgpd + // $customer->setNewsLetter(true); // No NewsLetter + // $customer->setIsActive(true); // No IsActive + $customer->setIsAccountConfigured(true); + $customer->setName('Doe'); + $customer->setSurname('John'); + $customer->setPhone('0123456789'); + // $customer->setBirthday(new \DateTime('1990-01-01')); // No Birthday + $customer->setCiv('Mr'); + $customer->setSiret('12345678901234'); + // $customer->setKbis('kbis_file'); // No Kbis + // $customer->setUpdatedAt($now); // No UpdatedAt + $customer->setCustomerId('cust_id_123'); + $customer->setVerificationCode('123456'); + $customer->setVerificationCodeExpiresAt($now->modify('+10min')); + + $this->assertEquals('customer@test.com', $customer->getEmail()); + $this->assertContains('ROLE_CUSTOMER', $customer->getRoles()); + $this->assertEquals('hash', $customer->getPassword()); + // $this->assertNotNull($customer->getCreateAt()); // Constructor sets it + $this->assertTrue($customer->isAccountConfigured()); + $this->assertEquals('Doe', $customer->getName()); + $this->assertEquals('John', $customer->getSurname()); + $this->assertEquals('0123456789', $customer->getPhone()); + $this->assertEquals('Mr', $customer->getCiv()); + $this->assertEquals('12345678901234', $customer->getSiret()); + $this->assertEquals('cust_id_123', $customer->getCustomerId()); + $this->assertEquals('123456', $customer->getVerificationCode()); + $this->assertEquals($now->modify('+10min')->format('Y-m-d H:i:s'), $customer->getVerificationCodeExpiresAt()->format('Y-m-d H:i:s')); + } + + public function testContratsCollection() + { + $customer = new Customer(); + $contrat = new Contrats(); + + $this->assertCount(0, $customer->getContrats()); + $customer->addContrat($contrat); + $this->assertCount(1, $customer->getContrats()); + $this->assertSame($customer, $contrat->getCustomer()); + + // No removeContrat method in entity + // $customer->removeContrat($contrat); + // $this->assertCount(0, $customer->getContrats()); + // $this->assertNull($contrat->getCustomer()); + } + + public function testDevisCollection() + { + $customer = new Customer(); + $devis = new Devis(); + + $this->assertCount(0, $customer->getDevis()); + $customer->addDevi($devis); // Use addDevi + $this->assertCount(1, $customer->getDevis()); + $this->assertSame($customer, $devis->getCustomer()); + + // No removeDevi method in entity + // $customer->removeDevi($devis); + // $this->assertCount(0, $customer->getDevis()); + // $this->assertNull($devis->getCustomer()); + } + + public function testCustomerAddressesCollection() + { + $customer = new Customer(); + $address = new CustomerAddress(); + + $this->assertCount(0, $customer->getCustomerAddresses()); + $customer->addCustomerAddress($address); + $this->assertCount(1, $customer->getCustomerAddresses()); + $this->assertSame($customer, $address->getCustomer()); + + // No removeCustomerAddress method in entity + // $customer->removeCustomerAddress($address); + // $this->assertCount(0, $customer->getCustomerAddresses()); + // $this->assertNull($address->getCustomer()); + } + + public function testOrderSessionsCollection() + { + $customer = new Customer(); + $orderSession = new OrderSession(); + + $this->assertCount(0, $customer->getOrderSessions()); + $customer->addOrderSession($orderSession); + $this->assertCount(1, $customer->getOrderSessions()); + $this->assertSame($customer, $orderSession->getCustomer()); + + $customer->removeOrderSession($orderSession); + $this->assertCount(0, $customer->getOrderSessions()); + $this->assertNull($orderSession->getCustomer()); + } + + public function testCustomerTrackingsCollection() + { + $customer = new Customer(); + $tracking = new CustomerTracking(); + + $this->assertCount(0, $customer->getCustomerTrackings()); + $customer->addCustomerTracking($tracking); + $this->assertCount(1, $customer->getCustomerTrackings()); + $this->assertSame($customer, $tracking->getCustomer()); + + $customer->removeCustomerTracking($tracking); + $this->assertCount(0, $customer->getCustomerTrackings()); + $this->assertNull($tracking->getCustomer()); + } +} diff --git a/tests/Entity/CustomerTrackingTest.php b/tests/Entity/CustomerTrackingTest.php new file mode 100644 index 0000000..c6accaa --- /dev/null +++ b/tests/Entity/CustomerTrackingTest.php @@ -0,0 +1,25 @@ +setCustomer($customer); + $tracking->setCreateAT($now); // Use createAT + $tracking->setTrackId('track_id_123'); // Use trackId + + $this->assertSame($customer, $tracking->getCustomer()); + $this->assertSame($now, $tracking->getCreateAT()); + $this->assertEquals('track_id_123', $tracking->getTrackId()); + } +} diff --git a/tests/Entity/DevisLineTest.php b/tests/Entity/DevisLineTest.php new file mode 100644 index 0000000..801078d --- /dev/null +++ b/tests/Entity/DevisLineTest.php @@ -0,0 +1,30 @@ +setDevi($devis); // Use setDevi + $devisLine->setProduct('Product X'); // Use setProduct + $devisLine->setPos(1); // Use setPos + $devisLine->setPriceHt(50.0); // Use setPriceHt + $devisLine->setPriceHtSup(10.0); // Use setPriceHtSup + $devisLine->setDay(2); // Use setDay + + $this->assertSame($devis, $devisLine->getDevi()); + $this->assertEquals('Product X', $devisLine->getProduct()); + $this->assertEquals(1, $devisLine->getPos()); + $this->assertEquals(50.0, $devisLine->getPriceHt()); + $this->assertEquals(10.0, $devisLine->getPriceHtSup()); + $this->assertEquals(2, $devisLine->getDay()); + } +} diff --git a/tests/Entity/DevisOptionsTest.php b/tests/Entity/DevisOptionsTest.php new file mode 100644 index 0000000..a9166c3 --- /dev/null +++ b/tests/Entity/DevisOptionsTest.php @@ -0,0 +1,26 @@ +setDevis($devis); + $devisOption->setOption('Option A'); // Use setOption + $devisOption->setPriceHt(25.0); // Use setPriceHt + $devisOption->setDetails('Some details'); // Use setDetails + + $this->assertSame($devis, $devisOption->getDevis()); + $this->assertEquals('Option A', $devisOption->getOption()); + $this->assertEquals(25.0, $devisOption->getPriceHt()); + $this->assertEquals('Some details', $devisOption->getDetails()); + } +} diff --git a/tests/Entity/DevisTest.php b/tests/Entity/DevisTest.php new file mode 100644 index 0000000..7dc277b --- /dev/null +++ b/tests/Entity/DevisTest.php @@ -0,0 +1,90 @@ +setCustomer($customer); + $devis->setNum('DEVIS-001'); + $devis->setCreateA($now); + $devis->setUpdateAt($now); // Use setUpdateAt + $devis->setState('pending'); + $devis->setSignatureId('sign123'); + $devis->setAddressShip($addressShip); + $devis->setBillAddress($billAddress); + $devis->setStartAt($now->modify('+1 day')); + $devis->setEndAt($now->modify('+2 days')); + $devis->setDevisFileName('devis.pdf'); + $devis->setDevisFileSize(1024); + $devis->setDevisDocuSealFileName('docuseal.pdf'); + $devis->setDevisDocuSealFileSize(2048); + $devis->setDevisSignedFileName('signed.pdf'); + $devis->setDevisSignedFileSize(3072); + $devis->setDevisAuditFileName('audit.pdf'); + $devis->setDevisAuditFileSize(4096); + + $this->assertSame($customer, $devis->getCustomer()); + $this->assertEquals('DEVIS-001', $devis->getNum()); + $this->assertEquals($now, $devis->getCreateA()); + $this->assertEquals($now, $devis->getUpdateAt()); // Use getUpdateAt + $this->assertEquals('pending', $devis->getState()); + $this->assertEquals('sign123', $devis->getSignatureId()); + $this->assertSame($addressShip, $devis->getAddressShip()); + $this->assertSame($billAddress, $devis->getBillAddress()); + $this->assertEquals($now->modify('+1 day'), $devis->getStartAt()); + $this->assertEquals($now->modify('+2 days'), $devis->getEndAt()); + $this->assertEquals('devis.pdf', $devis->getDevisFileName()); + $this->assertEquals(1024, $devis->getDevisFileSize()); + $this->assertEquals('docuseal.pdf', $devis->getDevisDocuSealFileName()); + $this->assertEquals(2048, $devis->getDevisDocuSealFileSize()); + $this->assertEquals('signed.pdf', $devis->getDevisSignedFileName()); + $this->assertEquals(3072, $devis->getDevisSignedFileSize()); + $this->assertEquals('audit.pdf', $devis->getDevisAuditFileName()); + $this->assertEquals(4096, $devis->getDevisAuditFileSize()); + } + + public function testDevisLinesCollection() + { + $devis = new Devis(); + $line = new DevisLine(); + + $this->assertCount(0, $devis->getDevisLines()); + $devis->addDevisLine($line); + $this->assertCount(1, $devis->getDevisLines()); + $this->assertSame($devis, $line->getDevi()); // Use getDevi + + $devis->removeDevisLine($line); + $this->assertCount(0, $devis->getDevisLines()); + $this->assertNull($line->getDevi()); // Use getDevi + } + + public function testDevisOptionsCollection() + { + $devis = new Devis(); + $option = new DevisOptions(); + + $this->assertCount(0, $devis->getDevisOptions()); + $devis->addDevisOption($option); + $this->assertCount(1, $devis->getDevisOptions()); + $this->assertSame($devis, $option->getDevis()); + + $devis->removeDevisOption($option); + $this->assertCount(0, $devis->getDevisOptions()); + $this->assertNull($option->getDevis()); + } +} diff --git a/tests/Entity/EtatLieuxTest.php b/tests/Entity/EtatLieuxTest.php new file mode 100644 index 0000000..a69ec4e --- /dev/null +++ b/tests/Entity/EtatLieuxTest.php @@ -0,0 +1,24 @@ +setContrat($contrat); + $etatLieux->setPrestataire($prestataire); + + $this->assertSame($contrat, $etatLieux->getContrat()); + $this->assertSame($prestataire, $etatLieux->getPrestataire()); + } +} diff --git a/tests/Entity/FactureTest.php b/tests/Entity/FactureTest.php new file mode 100644 index 0000000..88ed2f2 --- /dev/null +++ b/tests/Entity/FactureTest.php @@ -0,0 +1,27 @@ +setContrat($contrat); + $facture->setNum('INV-001'); + $facture->setCreateAt($now); + $facture->setUpdateAt($now); + + $this->assertSame($contrat, $facture->getContrat()); + $this->assertEquals('INV-001', $facture->getNum()); + $this->assertSame($now, $facture->getCreateAt()); + $this->assertSame($now, $facture->getUpdateAt()); + } +} diff --git a/tests/Entity/FormulesOptionsInclusTest.php b/tests/Entity/FormulesOptionsInclusTest.php new file mode 100644 index 0000000..6148136 --- /dev/null +++ b/tests/Entity/FormulesOptionsInclusTest.php @@ -0,0 +1,22 @@ +setName('Included Option'); + $optionsInclus->setFormule($formule); + + $this->assertEquals('Included Option', $optionsInclus->getName()); + $this->assertSame($formule, $optionsInclus->getFormule()); + } +} diff --git a/tests/Entity/FormulesProductInclusTest.php b/tests/Entity/FormulesProductInclusTest.php new file mode 100644 index 0000000..92aa98b --- /dev/null +++ b/tests/Entity/FormulesProductInclusTest.php @@ -0,0 +1,27 @@ + 'value']; + + $productInclus->setFormules($formules); + $productInclus->setPRODUCT($product); // Note: setPRODUCT is uppercase in entity + $productInclus->setConfig($config); + + $this->assertSame($formules, $productInclus->getFormules()); + $this->assertSame($product, $productInclus->getPRODUCT()); + $this->assertEquals($config, $productInclus->getConfig()); + } +} diff --git a/tests/Entity/FormulesRestrictionTest.php b/tests/Entity/FormulesRestrictionTest.php new file mode 100644 index 0000000..64a1216 --- /dev/null +++ b/tests/Entity/FormulesRestrictionTest.php @@ -0,0 +1,29 @@ + 1, 'max' => 5]; + + $restriction->setFormule($formule); + $restriction->setNbStructureMax(10); + $restriction->setRestrictionConfig($config); + $restriction->setNbAlimentaireMax(2); + $restriction->setNbBarhumsMax(3); + + $this->assertSame($formule, $restriction->getFormule()); + $this->assertEquals(10, $restriction->getNbStructureMax()); + $this->assertEquals($config, $restriction->getRestrictionConfig()); + $this->assertEquals(2, $restriction->getNbAlimentaireMax()); + $this->assertEquals(3, $restriction->getNbBarhumsMax()); + } +} diff --git a/tests/Entity/FormulesTest.php b/tests/Entity/FormulesTest.php new file mode 100644 index 0000000..3681c16 --- /dev/null +++ b/tests/Entity/FormulesTest.php @@ -0,0 +1,98 @@ +setName('Test Formule'); + $formules->setImageName('image.jpg'); + $formules->setImageSize(1024); + $formules->setUpdatedAt($now); + $formules->setType('package'); + $formules->setIsPublish(true); + $formules->setDescription('Formule description'); + $formules->setPrice1j(100.0); + $formules->setPrice2j(150.0); + $formules->setPrice5j(300.0); + $formules->setCaution(50.0); + $formules->setPos(1); + + $this->assertEquals('Test Formule', $formules->getName()); + $this->assertEquals('image.jpg', $formules->getImageName()); + $this->assertEquals(1024, $formules->getImageSize()); + $this->assertSame($now, $formules->getUpdatedAt()); + $this->assertEquals('package', $formules->getType()); + $this->assertTrue($formules->isPublish()); + $this->assertEquals('Formule description', $formules->getDescription()); + $this->assertEquals(100.0, $formules->getPrice1j()); + $this->assertEquals(150.0, $formules->getPrice2j()); + $this->assertEquals(300.0, $formules->getPrice5j()); + $this->assertEquals(50.0, $formules->getCaution()); + $this->assertEquals(1, $formules->getPos()); + } + + public function testSlug() + { + $formules = new Formules(); + // $formules->setId(1); // ID is auto-generated, cannot be set directly in unit test + $formules->setName('Test Formule'); + + $this->assertEquals('-test-formule', $formules->slug()); // ID will be null + } + + public function testFormulesProductInclusesCollection() + { + $formules = new Formules(); + $productInclus = new FormulesProductInclus(); + + $this->assertCount(0, $formules->getFormulesProductIncluses()); + $formules->addFormulesProductInclus($productInclus); + $this->assertCount(1, $formules->getFormulesProductIncluses()); + $this->assertSame($formules, $productInclus->getFormules()); + + $formules->removeFormulesProductInclus($productInclus); + $this->assertCount(0, $formules->getFormulesProductIncluses()); + $this->assertNull($productInclus->getFormules()); + } + + public function testFormulesOptionsInclusesCollection() + { + $formules = new Formules(); + $optionInclus = new FormulesOptionsInclus(); + + $this->assertCount(0, $formules->getFormulesOptionsIncluses()); + $formules->addFormulesOptionsInclus($optionInclus); + $this->assertCount(1, $formules->getFormulesOptionsIncluses()); + $this->assertSame($formules, $optionInclus->getFormule()); + + $formules->removeFormulesOptionsInclus($optionInclus); + $this->assertCount(0, $formules->getFormulesOptionsIncluses()); + $this->assertNull($optionInclus->getFormule()); + } + + public function testSetFormulesRestriction() + { + $formules = new Formules(); + $restriction = new FormulesRestriction(); + + $this->assertNull($formules->getFormulesRestriction()); + $formules->setFormulesRestriction($restriction); + $this->assertSame($restriction, $formules->getFormulesRestriction()); + $this->assertSame($formules, $restriction->getFormule()); + + $formules->setFormulesRestriction(null); + $this->assertNull($formules->getFormulesRestriction()); + $this->assertNull($restriction->getFormule()); + } +} diff --git a/tests/Entity/OptionsTest.php b/tests/Entity/OptionsTest.php new file mode 100644 index 0000000..de7d351 --- /dev/null +++ b/tests/Entity/OptionsTest.php @@ -0,0 +1,41 @@ +setName('Test Option'); + $options->setPriceHt(25.0); + $options->setStripeId('opt_123'); + $options->setImageName('option.jpg'); + $options->setImageSize(512); + $options->setUpdatedAt($now); + + $this->assertEquals('Test Option', $options->getName()); + $this->assertEquals(25.0, $options->getPriceHt()); + $this->assertEquals('opt_123', $options->getStripeId()); + $this->assertEquals('option.jpg', $options->getImageName()); + $this->assertEquals(512, $options->getImageSize()); + $this->assertSame($now, $options->getUpdatedAt()); + } + + public function testSlug() + { + $options = new Options(); + // ID is auto-generated, cannot be set directly in unit test + // For slug test, we will assume ID is null, or set it via reflection if absolutely needed. + // For simplicity, we will test the slug with a null ID. + $options->setName('Test Option'); + + $this->assertEquals('test-option', $options->slug()); + } +} diff --git a/tests/Entity/OrderSessionTest.php b/tests/Entity/OrderSessionTest.php new file mode 100644 index 0000000..da848ab --- /dev/null +++ b/tests/Entity/OrderSessionTest.php @@ -0,0 +1,60 @@ +setUuid($uuid); + $session->setProducts(['prod1', 'prod2']); + $session->setCustomer($customer); + // createdAt is set in constructor and PrePersist callback, so no direct setter test + // updatedAt is set by PreUpdate callback, so no direct setter test + $session->setState('completed'); + $session->setBillingAddress('123 Billing St'); + $session->setBillingZipCode('54321'); + $session->setBillingTown('Billingville'); + $session->setAdressEvent('123 Event St'); + $session->setAdress2Event('Apt 4B'); + $session->setAdress3Event('Building C'); + $session->setZipCodeEvent('98765'); + $session->setTownEvent('Eventown'); + $session->setType('personal'); + $session->setDetails('Event details'); + $session->setTypeSol('Hard'); + $session->setPente('medium'); + $session->setAccess('difficult'); + $session->setDistancePower(25.5); + + $this->assertEquals($uuid, $session->getUuid()); + $this->assertEquals(['prod1', 'prod2'], $session->getProducts()); + $this->assertSame($customer, $session->getCustomer()); + $this->assertNotNull($session->getCreatedAt()); // Set by constructor + $this->assertEquals('completed', $session->getState()); + $this->assertEquals('123 Billing St', $session->getBillingAddress()); + $this->assertEquals('54321', $session->getBillingZipCode()); + $this->assertEquals('Billingville', $session->getBillingTown()); + $this->assertEquals('123 Event St', $session->getAdressEvent()); + $this->assertEquals('Apt 4B', $session->getAdress2Event()); + $this->assertEquals('Building C', $session->getAdress3Event()); + $this->assertEquals('98765', $session->getZipCodeEvent()); + $this->assertEquals('Eventown', $session->getTownEvent()); + $this->assertEquals('personal', $session->getType()); + $this->assertEquals('Event details', $session->getDetails()); + $this->assertEquals('Hard', $session->getTypeSol()); + $this->assertEquals('medium', $session->getPente()); + $this->assertEquals('difficult', $session->getAccess()); + $this->assertEquals(25.5, $session->getDistancePower()); + } +} diff --git a/tests/Entity/PrestaireTest.php b/tests/Entity/PrestaireTest.php new file mode 100644 index 0000000..2e17f5e --- /dev/null +++ b/tests/Entity/PrestaireTest.php @@ -0,0 +1,50 @@ +setEmail('prestaire@test.com'); + $prestaire->setName('PrestaireName'); + $prestaire->setSurname('PrestaireSurname'); + $prestaire->setPhone('0123456789'); + $prestaire->setRoles(['ROLE_PRESTAIRE']); + + $this->assertEquals('prestaire@test.com', $prestaire->getEmail()); + $this->assertEquals('PrestaireName', $prestaire->getName()); + $this->assertEquals('PrestaireSurname', $prestaire->getSurname()); + $this->assertEquals('0123456789', $prestaire->getPhone()); + $this->assertContains('ROLE_PRESTAIRE', $prestaire->getRoles()); + // $this->assertNull($prestaire->getPassword()); // As per entity's getPassword() TODO + $this->assertEquals('prestaire@test.com', $prestaire->getUserIdentifier()); + } + + public function testEtatLieuxesCollection() + { + $prestaire = new Prestaire(); + $etatLieux = new EtatLieux(); + + $this->assertCount(0, $prestaire->getEtatLieuxes()); + $prestaire->addEtatLieux($etatLieux); + $this->assertCount(1, $prestaire->getEtatLieuxes()); + $this->assertSame($prestaire, $etatLieux->getPrestataire()); + + $prestaire->removeEtatLieux($etatLieux); + $this->assertCount(0, $prestaire->getEtatLieuxes()); + $this->assertNull($etatLieux->getPrestataire()); + } + + public function testEraseCredentials() + { + $prestaire = new Prestaire(); + $prestaire->eraseCredentials(); // Should do nothing as per entity's eraseCredentials() TODO + $this->assertTrue(true); // Just ensure it doesn't crash + } +} diff --git a/tests/Entity/ProductDocTest.php b/tests/Entity/ProductDocTest.php new file mode 100644 index 0000000..f71dbcc --- /dev/null +++ b/tests/Entity/ProductDocTest.php @@ -0,0 +1,48 @@ +setProduct($product); + $productDoc->setName('Document 1'); + $productDoc->setIsPublic(true); + $productDoc->setDocProductName('doc1.pdf'); + $productDoc->setDocProductSize(1024); + $productDoc->setUpdatedAt($now); + + $this->assertSame($product, $productDoc->getProduct()); + $this->assertEquals('Document 1', $productDoc->getName()); + $this->assertTrue($productDoc->isPublic()); + $this->assertEquals('doc1.pdf', $productDoc->getDocProductName()); + $this->assertEquals(1024, $productDoc->getDocProductSize()); + $this->assertSame($now, $productDoc->getUpdatedAt()); + } + + public function testJson() + { + $product = new Product(); + $product->setName('Main Product'); + + $productDoc = new ProductDoc(); + $productDoc->setProduct($product); + $productDoc->setName('Doc Name'); + + $expectedJson = json_encode([ + 'name' => 'Doc Name', + 'product' => 'Main Product', + ]); + + $this->assertEquals($expectedJson, $productDoc->json()); + } +} diff --git a/tests/Entity/ProductTest.php b/tests/Entity/ProductTest.php new file mode 100644 index 0000000..7d37b83 --- /dev/null +++ b/tests/Entity/ProductTest.php @@ -0,0 +1,153 @@ +setRef('PROD-001'); + $product->setCategory('Category A'); + $product->setName('Test Product'); + $product->setPriceDay(10.0); + $product->setPriceSup(5.0); + $product->setCaution(20.0); + $product->setImageName('product.jpg'); + $product->setImageSize(1024); + $product->setUpdatedAt($now); + $product->setProductId('ext_prod_id'); + $product->setDescription('Product description'); + $product->setQt(5); + $product->setDimW(100.0); + $product->setDimH(50.0); + $product->setDimP(20.0); + + $this->assertEquals('PROD-001', $product->getRef()); + $this->assertEquals('Category A', $product->getCategory()); + $this->assertEquals('Test Product', $product->getName()); + $this->assertEquals(10.0, $product->getPriceDay()); + $this->assertEquals(5.0, $product->getPriceSup()); + $this->assertEquals(20.0, $product->getCaution()); + $this->assertEquals('product.jpg', $product->getImageName()); + $this->assertEquals(1024, $product->getImageSize()); + $this->assertSame($now, $product->getUpdatedAt()); + $this->assertEquals('ext_prod_id', $product->getProductId()); + $this->assertEquals('Product description', $product->getDescription()); + $this->assertEquals(5, $product->getQt()); + $this->assertEquals(100.0, $product->getDimW()); + $this->assertEquals(50.0, $product->getDimH()); + $this->assertEquals(20.0, $product->getDimP()); + } + + public function testSlug() + { + $product = new Product(); + // $product->setId(1); // ID is auto-generated, cannot be set directly in unit test + $product->setName('Awesome Product'); + + $this->assertEquals('awesome-product', $product->slug()); + } + + public function testJson() + { + $product = new Product(); + // $product->setId(1); // ID is auto-generated + $product->setRef('PROD-JSON'); + $product->setName('JSON Product'); + + $expectedJson = json_encode([ + 'id' => null, // ID is null for new entity + 'ref' => 'PROD-JSON', + 'name' => 'JSON Product', + ]); + + $this->assertEquals($expectedJson, $product->json()); + } + + public function testProductReservesCollection() + { + $product = new Product(); + $reserve = new ProductReserve(); + + $this->assertCount(0, $product->getProductReserves()); + $product->addProductReserf($reserve); // Typo: addProductReserf + $this->assertCount(1, $product->getProductReserves()); + $this->assertSame($product, $reserve->getProduct()); + + $product->removeProductReserf($reserve); // Typo: removeProductReserf + $this->assertCount(0, $product->getProductReserves()); + $this->assertNull($reserve->getProduct()); + } + + public function testProductDocsCollection() + { + $product = new Product(); + $doc = new ProductDoc(); + + $this->assertCount(0, $product->getProductDocs()); + $product->addProductDoc($doc); + $this->assertCount(1, $product->getProductDocs()); + $this->assertSame($product, $doc->getProduct()); + + $product->removeProductDoc($doc); + $this->assertCount(0, $product->getProductDocs()); + $this->assertNull($doc->getProduct()); + } + + public function testFormulesProductInclusesCollection() + { + $product = new Product(); + $inclus = new FormulesProductInclus(); + + $this->assertCount(0, $product->getFormulesProductIncluses()); + $product->addFormulesProductInclus($inclus); + $this->assertCount(1, $product->getFormulesProductIncluses()); + $this->assertSame($product, $inclus->getPRODUCT()); + + $product->removeFormulesProductInclus($inclus); + $this->assertCount(0, $product->getFormulesProductIncluses()); + $this->assertNull($inclus->getPRODUCT()); + } + + public function testProductPhotosCollection() + { + $product = new Product(); + $photo = new ProductPhotos(); + + $this->assertCount(0, $product->getProductPhotos()); + $product->addProductPhoto($photo); + $this->assertCount(1, $product->getProductPhotos()); + $this->assertSame($product, $photo->getProduct()); + + $product->removeProductPhoto($photo); + $this->assertCount(0, $product->getProductPhotos()); + $this->assertNull($photo->getProduct()); + } + + public function testProductVideosCollection() + { + $product = new Product(); + $video = new ProductVideo(); + + $this->assertCount(0, $product->getProductVideos()); + $product->addProductVideo($video); + $this->assertCount(1, $product->getProductVideos()); + $this->assertSame($product, $video->getProduct()); + + $product->removeProductVideo($video); + $this->assertCount(0, $product->getProductVideos()); + $this->assertNull($video->getProduct()); + } +} diff --git a/tests/Event/Object/EventAdminCreateTest.php b/tests/Event/Object/EventAdminCreateTest.php new file mode 100644 index 0000000..7cba6dc --- /dev/null +++ b/tests/Event/Object/EventAdminCreateTest.php @@ -0,0 +1,23 @@ +createMock(Account::class); + $requestedAccount = $this->createMock(Account::class); + + $event = new EventAdminCreate($account, $requestedAccount); + + $this->assertSame($account, $event->getAccount()); + $this->assertSame($requestedAccount, $event->getRequestedAccount()); + } +} diff --git a/tests/Event/Object/EventAdminDeletedTest.php b/tests/Event/Object/EventAdminDeletedTest.php new file mode 100644 index 0000000..c8214ea --- /dev/null +++ b/tests/Event/Object/EventAdminDeletedTest.php @@ -0,0 +1,23 @@ +createMock(Account::class); + $requestedAccount = $this->createMock(Account::class); + + $event = new EventAdminDeleted($account, $requestedAccount); + + $this->assertSame($account, $event->getAccount()); + $this->assertSame($requestedAccount, $event->getRequestedAccount()); + } +} diff --git a/tests/Event/Service/AdminEventTest.php b/tests/Event/Service/AdminEventTest.php new file mode 100644 index 0000000..7041da2 --- /dev/null +++ b/tests/Event/Service/AdminEventTest.php @@ -0,0 +1,144 @@ +mailer = $this->createMock(Mailer::class); + $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + + $this->adminEvent = new AdminEvent( + $this->mailer, + $this->urlGenerator, + $this->entityManager + ); + } + + public function testOnAdminCreate() + { + $account = $this->createMock(Account::class); + $account->method('getId')->willReturn(1); + $account->method('getEmail')->willReturn('test@example.com'); + $account->method('getFirstName')->willReturn('John'); + $account->method('getName')->willReturn('Doe'); + + $requestedAccount = $this->createMock(Account::class); + + $event = new EventAdminCreate($account, $requestedAccount); + + $repo = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->with(AccountResetPasswordRequest::class)->willReturn($repo); + $repo->method('findOneBy')->willReturn(null); + + $this->entityManager->expects($this->once())->method('persist'); + $this->entityManager->expects($this->once())->method('flush'); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->willReturn('http://example.com/reset'); + + $this->mailer->expects($this->once()) + ->method('send') + ->with( + 'test@example.com', + 'John Doe', + '[Intranet Ludikevent] Activation de votre accès administrateur' + ); + + $this->adminEvent->onAdminCreate($event); + } + + public function testOnAdminCreateExistingValidRequest() + { + $account = $this->createMock(Account::class); + $account->method('getId')->willReturn(1); + $account->method('getEmail')->willReturn('test@example.com'); + $requestedAccount = $this->createMock(Account::class); + $event = new EventAdminCreate($account, $requestedAccount); + + $existingRequest = new AccountResetPasswordRequest(); + $existingRequest->setExpiresAt(new \DateTimeImmutable('+1 hour')); + $existingRequest->setToken('existing_token'); + + $repo = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->with(AccountResetPasswordRequest::class)->willReturn($repo); + $repo->method('findOneBy')->willReturn($existingRequest); + + // Should NOT persist a new one, but reuse existing + $this->entityManager->expects($this->never())->method('persist'); + + // Should generate URL with existing token + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with( + 'app_forgot_password_confirm', + ['id' => 1, 'token' => 'existing_token'] + ); + + $this->adminEvent->onAdminCreate($event); + } + + public function testOnAdminCreateExistingExpiredRequest() + { + $account = $this->createMock(Account::class); + $account->method('getId')->willReturn(1); + $account->method('getEmail')->willReturn('test@example.com'); + $requestedAccount = $this->createMock(Account::class); + $event = new EventAdminCreate($account, $requestedAccount); + + $existingRequest = new AccountResetPasswordRequest(); + $existingRequest->setExpiresAt(new \DateTimeImmutable('-1 hour')); + + $repo = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->with(AccountResetPasswordRequest::class)->willReturn($repo); + $repo->method('findOneBy')->willReturn($existingRequest); + + // Should remove expired + $this->entityManager->expects($this->once())->method('remove')->with($existingRequest); + // Should persist new one + $this->entityManager->expects($this->atLeastOnce())->method('persist'); + // Flush called for remove and persist + $this->entityManager->expects($this->atLeast(2))->method('flush'); + + $this->adminEvent->onAdminCreate($event); + } + + public function testOnAdminDeleted() + { + $account = $this->createMock(Account::class); + $requestedAccount = $this->createMock(Account::class); + + $event = new EventAdminDeleted($account, $requestedAccount); + + $this->mailer->expects($this->exactly(2)) + ->method('send') + ->with( + $this->stringContains('@'), // Simple check for email arg + $this->stringContains('Notification'), + "[Intranet Ludikevent] - Suppression d'un administrateur" + ); + + $this->adminEvent->onAdminDeleted($event); + } +} diff --git a/tests/Event/Service/LoginStatsSubscriberTest.php b/tests/Event/Service/LoginStatsSubscriberTest.php new file mode 100644 index 0000000..6320a98 --- /dev/null +++ b/tests/Event/Service/LoginStatsSubscriberTest.php @@ -0,0 +1,62 @@ +entityManager = $this->createMock(EntityManagerInterface::class); + $this->subscriber = new LoginStatsSubscriber($this->entityManager); + } + + public function testOnLoginSuccessWithAccount() + { + $user = $this->createMock(Account::class); + $request = new Request([], [], [], [], [], ['REMOTE_ADDR' => '127.0.0.1']); + $request->headers->set('User-Agent', 'TestAgent'); + + // Manually setting client IP on Request is tricky without relying on 'REMOTE_ADDR' server var or trusted proxies + // But getClientIp() defaults to null or 127.0.0.1 depending on setup. + // We can just rely on the default behavior for this test or mock the request if it was an interface/mockable. + // Since Request is a concrete class, we use it as is. + + $event = $this->createMock(LoginSuccessEvent::class); + $event->method('getUser')->willReturn($user); + $event->method('getRequest')->willReturn($request); + + $this->entityManager->expects($this->once()) + ->method('persist') + ->with($this->isInstanceOf(AccountLoginRegister::class)); + + $this->entityManager->expects($this->once())->method('flush'); + + $this->subscriber->onLoginSuccess($event); + } + + public function testOnLoginSuccessWithNonAccountUser() + { + $user = $this->createMock(UserInterface::class); + $event = $this->createMock(LoginSuccessEvent::class); + $event->method('getUser')->willReturn($user); + + $this->entityManager->expects($this->never())->method('persist'); + $this->entityManager->expects($this->never())->method('flush'); + + $this->subscriber->onLoginSuccess($event); + } +} diff --git a/tests/Event/Signature/ContratEventTest.php b/tests/Event/Signature/ContratEventTest.php new file mode 100644 index 0000000..c33ad20 --- /dev/null +++ b/tests/Event/Signature/ContratEventTest.php @@ -0,0 +1,20 @@ +createMock(Contrats::class); + $event = new ContratEvent($contrats); + + $this->assertSame($contrats, $event->getContrats()); + } +} diff --git a/tests/Event/Signature/ContratSubscriberTest.php b/tests/Event/Signature/ContratSubscriberTest.php new file mode 100644 index 0000000..0245b95 --- /dev/null +++ b/tests/Event/Signature/ContratSubscriberTest.php @@ -0,0 +1,135 @@ +mailer = $this->createMock(Mailer::class); + $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->kernel = $this->createMock(KernelInterface::class); + $this->storage = $this->createMock(StorageInterface::class); + $this->uploaderHelper = new UploaderHelper($this->storage); // Real class as it's final + + $this->tempDir = sys_get_temp_dir() . '/contrat_test_' . uniqid(); + mkdir($this->tempDir . '/public', 0777, true); + + $this->subscriber = new ContratSubscriber( + $this->mailer, + $this->urlGenerator, + $this->kernel, + $this->uploaderHelper + ); + + $_ENV['CONTRAT_BASEURL'] = 'https://baseurl.com'; + } + + protected function tearDown(): void + { + $this->removeDirectory($this->tempDir); + } + + public function testOnContratSendWithAttachment() + { + // 1. Setup File + $relativePath = '/uploads/contrats/c1.pdf'; + mkdir(dirname($this->tempDir . '/public' . $relativePath), 0777, true); + file_put_contents($this->tempDir . '/public' . $relativePath, 'PDF Content'); + + $this->kernel->method('getProjectDir')->willReturn($this->tempDir); + + // 2. Setup Entities + $customer = $this->createMock(Customer::class); + $customer->method('getEmail')->willReturn('cust@test.com'); + $customer->method('getSurname')->willReturn('John'); + $customer->method('getName')->willReturn('Doe'); + + $contrat = $this->createMock(Contrats::class); + $contrat->method('getCustomer')->willReturn($customer); + $contrat->method('getNumReservation')->willReturn('RES-123'); + + $this->storage->method('resolveUri')->willReturn($relativePath); + + $event = new ContratEvent($contrat); + + // 3. Expectations + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('gestion_contrat_view', ['num' => 'RES-123']); + + $this->mailer->expects($this->once()) + ->method('send') + ->with( + 'cust@test.com', + 'John Doe', + '[Ludikevent] - Contrat de location N°RES-123', + 'mails/sign/contrat.twig', + $this->anything(), + $this->callback(function($attachments) { + return count($attachments) === 1; + }) + ); + + $this->subscriber->onContratSend($event); + } + + public function testOnContratSendWithoutAttachment() + { + // No file created + $this->kernel->method('getProjectDir')->willReturn($this->tempDir); + + $customer = $this->createMock(Customer::class); + $customer->method('getEmail')->willReturn('cust@test.com'); // Mock email + $contrat = $this->createMock(Contrats::class); + $contrat->method('getCustomer')->willReturn($customer); + $contrat->method('getNumReservation')->willReturn('RES-123'); + + $this->storage->method('resolveUri')->willReturn(null); + + $event = new ContratEvent($contrat); + + $this->mailer->expects($this->once()) + ->method('send') + ->with( + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything(), + [] // Empty attachments + ); + + $this->subscriber->onContratSend($event); + } + + private function removeDirectory($dir) { + if (!is_dir($dir)) return; + $files = array_diff(scandir($dir), array('.','..')); + foreach ($files as $file) { + (is_dir("$dir/$file")) ? $this->removeDirectory("$dir/$file") : unlink("$dir/$file"); + } + rmdir($dir); + } +} diff --git a/tests/Event/Signature/DevisSendTest.php b/tests/Event/Signature/DevisSendTest.php new file mode 100644 index 0000000..6919fe5 --- /dev/null +++ b/tests/Event/Signature/DevisSendTest.php @@ -0,0 +1,20 @@ +createMock(Devis::class); + $event = new DevisSend($devis); + + $this->assertSame($devis, $event->getDevis()); + } +} diff --git a/tests/Event/Signature/DevisSubscriberTest.php b/tests/Event/Signature/DevisSubscriberTest.php new file mode 100644 index 0000000..709111a --- /dev/null +++ b/tests/Event/Signature/DevisSubscriberTest.php @@ -0,0 +1,68 @@ +entityManager = $this->createMock(EntityManagerInterface::class); + $this->mailer = $this->createMock(Mailer::class); + $this->client = $this->createMock(Client::class); + + $this->subscriber = new DevisSubscriber( + $this->entityManager, + $this->mailer, + $this->client + ); + } + + public function testOnDevisSend() + { + $customer = $this->createMock(Customer::class); + $customer->method('getEmail')->willReturn('cust@test.com'); + $customer->method('getName')->willReturn('Doe'); + $customer->method('getSurname')->willReturn('John'); + + $devis = $this->createMock(Devis::class); + $devis->method('getCustomer')->willReturn($customer); + $devis->method('getSignatureId')->willReturn('sign_id_123'); + + $event = new DevisSend($devis); + + $this->client->expects($this->once()) + ->method('getLinkSign') + ->with('sign_id_123') + ->willReturn('http://sign.link'); + + $this->mailer->expects($this->once()) + ->method('send') + ->with( + 'cust@test.com', + 'Doe John', + '[Signature Ludikevent] - Signature de votre devis pour votre location', + 'mails/sign/devis.twig', + $this->callback(function($context) use ($devis) { + return $context['devis'] === $devis && $context['signLink'] === 'http://sign.link'; + }) + ); + + $this->subscriber->onDevisSend($event); + } +} diff --git a/tests/Logger/AppLoggerTest.php b/tests/Logger/AppLoggerTest.php new file mode 100644 index 0000000..1dd2156 --- /dev/null +++ b/tests/Logger/AppLoggerTest.php @@ -0,0 +1,84 @@ +entityManager = $this->createMock(EntityManagerInterface::class); + $this->security = $this->createMock(Security::class); + $this->requestStack = $this->createMock(RequestStack::class); + + $this->logger = new AppLogger( + $this->entityManager, + $this->security, + $this->requestStack + ); + } + + public function testRecordWithAccountUser() + { + $user = $this->createMock(Account::class); + $this->security->method('getUser')->willReturn($user); + + $request = new Request(); + $request->headers->set('User-Agent', 'TestAgent'); + + $this->requestStack->method('getCurrentRequest')->willReturn($request); + + $this->entityManager->expects($this->once()) + ->method('persist') + ->with($this->isInstanceOf(AuditLog::class)); + + $this->entityManager->expects($this->once())->method('flush'); + + $this->logger->record('TEST_TYPE', 'Test Message'); + } + + public function testRecordWithNonAccountUser() + { + $user = $this->createMock(UserInterface::class); + $this->security->method('getUser')->willReturn($user); + + $this->entityManager->expects($this->never())->method('persist'); + $this->entityManager->expects($this->never())->method('flush'); + + $this->logger->record('TEST_TYPE', 'Test Message'); + } + + public function testRecordWithNoRequest() + { + $user = $this->createMock(Account::class); + $this->security->method('getUser')->willReturn($user); + + $this->requestStack->method('getCurrentRequest')->willReturn(null); + + $this->entityManager->expects($this->once()) + ->method('persist') + ->with($this->callback(function(AuditLog $log) { + return $log->getPath() === 'CLI/Internal'; + })); + + $this->entityManager->expects($this->once())->method('flush'); + + $this->logger->record('TEST_TYPE', 'Test Message'); + } +} diff --git a/tests/Repository/AccountRepositoryTest.php b/tests/Repository/AccountRepositoryTest.php new file mode 100644 index 0000000..8a49d32 --- /dev/null +++ b/tests/Repository/AccountRepositoryTest.php @@ -0,0 +1,106 @@ +entityManager = $kernel->getContainer() + ->get('doctrine') + ->getManager(); + + $this->repository = $this->entityManager->getRepository(Account::class); + } + + protected function tearDown(): void + { + parent::tearDown(); + $this->entityManager->close(); + $this->entityManager = null; + $this->repository = null; + } + + public function testFindAdmin() + { + // 1. Create Admins + $admin = new Account(); + $admin->setEmail('admin_' . uniqid() . '@test.com'); + $admin->setRoles(['ROLE_ADMIN']); + $admin->setPassword('password'); + $admin->setName('Admin'); + $admin->setFirstName('User'); + $admin->setUsername('admin_user_' . uniqid()); + $admin->setUuid(Uuid::v4()); + $admin->setIsActif(true); + $admin->setIsFirstLogin(false); + $this->entityManager->persist($admin); + + // 2. Create Non-Admin + $user = new Account(); + $user->setEmail('user_' . uniqid() . '@test.com'); + $user->setRoles(['ROLE_USER']); + $user->setPassword('password'); + $user->setName('User'); + $user->setFirstName('Normal'); + $user->setUsername('normal_user_' . uniqid()); + $user->setUuid(Uuid::v4()); + $user->setIsActif(true); + $user->setIsFirstLogin(false); + $this->entityManager->persist($user); + + $this->entityManager->flush(); + + // 3. Test findAdmin + $admins = $this->repository->findAdmin(); + + $this->assertGreaterThanOrEqual(1, count($admins)); + + $found = false; + foreach ($admins as $a) { + if ($a->getEmail() === 'admin@test.com') { + $found = true; + } + // Ensure no user is returned (this might be tricky if other tests persist data, + // but we check if our non-admin is in the list) + if ($a->getEmail() === 'user@test.com') { + $this->fail('Non-admin user returned in findAdmin()'); + } + } + + $this->assertTrue($found, 'Admin user not found in findAdmin() result'); + } + + public function testUpgradePassword() + { + $user = new Account(); + $user->setEmail('upgrade_' . uniqid() . '@test.com'); + $user->setRoles(['ROLE_USER']); + $user->setPassword('old_hash'); + $user->setName('Upgrade'); + $user->setFirstName('User'); + $user->setUsername('upgrade_user_' . uniqid()); + $user->setUuid(Uuid::v4()); + $user->setIsActif(true); + $user->setIsFirstLogin(false); + + $this->entityManager->persist($user); + $this->entityManager->flush(); + + $this->repository->upgradePassword($user, 'new_encoded_password'); + + $updatedUser = $this->repository->find($user->getId()); + $this->assertEquals('new_encoded_password', $updatedUser->getPassword()); + } +} diff --git a/tests/Repository/ContratsRepositoryTest.php b/tests/Repository/ContratsRepositoryTest.php new file mode 100644 index 0000000..a5da804 --- /dev/null +++ b/tests/Repository/ContratsRepositoryTest.php @@ -0,0 +1,117 @@ +entityManager = $kernel->getContainer() + ->get('doctrine') + ->getManager(); + + $this->repository = $this->entityManager->getRepository(Contrats::class); + } + + protected function tearDown(): void + { + parent::tearDown(); + $this->entityManager->close(); + $this->entityManager = null; + $this->repository = null; + } + + public function testFindBetweenDates() + { + $customer = new Customer(); + $customer->setEmail('contrat_' . uniqid() . '@test.com'); + $customer->setName('Test'); + $customer->setSurname('Contrat'); + $customer->setPhone('0600000000'); + $customer->setCiv('Mr'); + $customer->setType('pro'); + $this->entityManager->persist($customer); + + // 1. Create Contrats + // Target: 2026-06-15 + $contratTarget = new Contrats(); + $contratTarget->setDateAt(new \DateTimeImmutable('2026-06-15 12:00:00')); + $contratTarget->setEndAt(new \DateTimeImmutable('2026-06-16 12:00:00')); + $contratTarget->setCreateAt(new \DateTimeImmutable()); + $contratTarget->setNumReservation('RES-TARGET'); + $contratTarget->setAddressEvent('123 Main St'); + $contratTarget->setZipCodeEvent('12345'); + $contratTarget->setTownEvent('City'); + $contratTarget->setType('event'); + $contratTarget->setPente('flat'); + $contratTarget->setIsSigned(false); + $contratTarget->setCustomer($customer); + $this->entityManager->persist($contratTarget); + + // Before: 2026-06-01 + $contratBefore = new Contrats(); + $contratBefore->setDateAt(new \DateTimeImmutable('2026-06-01 12:00:00')); + $contratBefore->setEndAt(new \DateTimeImmutable('2026-06-02 12:00:00')); + $contratBefore->setCreateAt(new \DateTimeImmutable()); + $contratBefore->setNumReservation('RES-BEFORE'); + $contratBefore->setAddressEvent('123 Main St'); + $contratBefore->setZipCodeEvent('12345'); + $contratBefore->setTownEvent('City'); + $contratBefore->setType('event'); + $contratBefore->setPente('flat'); + $contratBefore->setIsSigned(false); + $contratBefore->setCustomer($customer); + $this->entityManager->persist($contratBefore); + + // After: 2026-07-01 + $contratAfter = new Contrats(); + $contratAfter->setDateAt(new \DateTimeImmutable('2026-07-01 12:00:00')); + $contratAfter->setEndAt(new \DateTimeImmutable('2026-07-02 12:00:00')); + $contratAfter->setCreateAt(new \DateTimeImmutable()); + $contratAfter->setNumReservation('RES-AFTER'); + $contratAfter->setAddressEvent('123 Main St'); + $contratAfter->setZipCodeEvent('12345'); + $contratAfter->setTownEvent('City'); + $contratAfter->setType('event'); + $contratAfter->setPente('flat'); + $contratAfter->setIsSigned(false); + $contratAfter->setCustomer($customer); + $this->entityManager->persist($contratAfter); + + $this->entityManager->flush(); + + // 2. Search Interval: 2026-06-10 to 2026-06-20 + $start = new \DateTimeImmutable('2026-06-10 00:00:00'); + $end = new \DateTimeImmutable('2026-06-20 00:00:00'); + + $results = $this->repository->findBetweenDates($start, $end); + + $this->assertGreaterThanOrEqual(1, count($results)); + + $foundTarget = false; + foreach ($results as $contrat) { + if ($contrat->getNumReservation() === 'RES-TARGET') { + $foundTarget = true; + } + if ($contrat->getNumReservation() === 'RES-BEFORE') { + $this->fail('Contrat BEFORE interval should not be found'); + } + if ($contrat->getNumReservation() === 'RES-AFTER') { + $this->fail('Contrat AFTER interval should not be found'); + } + } + + $this->assertTrue($foundTarget, 'Target contrat not found'); + } +} diff --git a/tests/Security/AccessDeniedHandlerTest.php b/tests/Security/AccessDeniedHandlerTest.php new file mode 100644 index 0000000..d2e73a4 --- /dev/null +++ b/tests/Security/AccessDeniedHandlerTest.php @@ -0,0 +1,68 @@ +urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->twig = $this->createMock(Environment::class); + $this->handler = new AccessDeniedHandler($this->urlGenerator, $this->twig); + } + + public function testHandleAdminPathRedirectsToHome() + { + $request = Request::create('/admin/dashboard'); + $exception = new AccessDeniedException(); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('app_home') + ->willReturn('/home'); + + $response = $this->handler->handle($request, $exception); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/home', $response->getTargetUrl()); + } + + public function testHandleJsonRequestReturnsForbidden() + { + $request = Request::create('/api/data'); + $request->headers->set('Accept', 'application/json'); + $exception = new AccessDeniedException(); + + $response = $this->handler->handle($request, $exception); + + $this->assertInstanceOf(JsonResponse::class, $response); + $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode()); + } + + public function testHandleDefaultReturnsForbidden() + { + $request = Request::create('/some/other/path'); + $exception = new AccessDeniedException(); + + $response = $this->handler->handle($request, $exception); + + $this->assertInstanceOf(JsonResponse::class, $response); + $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode()); + } +} diff --git a/tests/Security/AuthenticationEntryPointTest.php b/tests/Security/AuthenticationEntryPointTest.php new file mode 100644 index 0000000..81bc145 --- /dev/null +++ b/tests/Security/AuthenticationEntryPointTest.php @@ -0,0 +1,119 @@ +urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->tokenStorage = $this->createMock(TokenStorageInterface::class); + $this->entryPoint = new AuthenticationEntryPoint($this->urlGenerator, $this->tokenStorage); + } + + public function testStartJsonRequestReturnsForbidden() + { + $request = Request::create('/api/resource'); + $request->headers->set('Accept', 'application/json'); + + $response = $this->entryPoint->start($request); + + $this->assertInstanceOf(JsonResponse::class, $response); + $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode()); + } + + public function testStartCrmPathWithCustomerRedirectsToHome() + { + $request = Request::create('/crm/dashboard'); + + $customer = $this->createMock(Customer::class); + $token = $this->createMock(TokenInterface::class); + $token->method('getUser')->willReturn($customer); + $this->tokenStorage->method('getToken')->willReturn($token); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('app_home') + ->willReturn('/home'); + + $response = $this->entryPoint->start($request); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/home', $response->getTargetUrl()); + } + + public function testStartCrmPathWithoutUserRedirectsToHome() + { + $request = Request::create('/crm/dashboard'); + + $this->tokenStorage->method('getToken')->willReturn(null); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('app_home') + ->willReturn('/home'); + + $response = $this->entryPoint->start($request); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/home', $response->getTargetUrl()); + } + + public function testStartReservationPathWithoutUserRedirectsToReservationLogin() + { + $request = Request::create('/reservation/book'); + + $this->tokenStorage->method('getToken')->willReturn(null); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('reservation_login') + ->willReturn('/reservation/login'); + + $response = $this->entryPoint->start($request); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/reservation/login', $response->getTargetUrl()); + } + + public function testStartReservationPathWithUserRedirectsToHomeOnlyBecauseDefaultFallback() + { + // Note: The logic in AuthenticationEntryPoint for /reservation only handles !$user. + // If user exists (Account or Customer), it falls through to the default return at the end. + + $request = Request::create('/reservation/book'); + + $user = $this->createMock(Account::class); + $token = $this->createMock(TokenInterface::class); + $token->method('getUser')->willReturn($user); + $this->tokenStorage->method('getToken')->willReturn($token); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('app_home') + ->willReturn('/home'); + + $response = $this->entryPoint->start($request); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/home', $response->getTargetUrl()); + } +} diff --git a/tests/Security/CustomerAuthenticatorTest.php b/tests/Security/CustomerAuthenticatorTest.php new file mode 100644 index 0000000..c90b65c --- /dev/null +++ b/tests/Security/CustomerAuthenticatorTest.php @@ -0,0 +1,86 @@ +urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->authenticator = new CustomerAuthenticator($this->urlGenerator, $this->entityManager); + } + + public function testSupports() + { + $request = Request::create('/reservation/login', 'POST'); + $request->attributes->set('_route', 'reservation_login'); + + $this->assertTrue($this->authenticator->supports($request)); + + $requestInvalid = Request::create('/reservation/login', 'GET'); + $requestInvalid->attributes->set('_route', 'reservation_login'); + $this->assertFalse($this->authenticator->supports($requestInvalid)); + } + + public function testAuthenticate() + { + $request = Request::create('/login', 'POST', [ + '_username' => 'test@test.com', + '_password' => 'password', + '_csrf_token' => 'token' + ]); + + $session = $this->createMock(SessionInterface::class); + $request->setSession($session); + + $repository = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->with(Customer::class)->willReturn($repository); + $repository->method('findOneBy')->with(['email' => 'test@test.com'])->willReturn(new Customer()); + + $passport = $this->authenticator->authenticate($request); + + $this->assertInstanceOf(Passport::class, $passport); + $this->assertTrue($passport->hasBadge(UserBadge::class)); + $this->assertTrue($passport->hasBadge(CsrfTokenBadge::class)); + } + + public function testOnAuthenticationSuccessRedirectsToReservation() + { + $request = Request::create('/login'); + $session = $this->createMock(SessionInterface::class); + $request->setSession($session); + + $token = $this->createMock(TokenInterface::class); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('reservation') + ->willReturn('/reservation'); + + $response = $this->authenticator->onAuthenticationSuccess($request, $token, 'main'); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/reservation', $response->getTargetUrl()); + } +} diff --git a/tests/Security/ErrorListenerTest.php b/tests/Security/ErrorListenerTest.php new file mode 100644 index 0000000..6d39337 --- /dev/null +++ b/tests/Security/ErrorListenerTest.php @@ -0,0 +1,88 @@ +twig = $this->createMock(Environment::class); + $this->listener = new ErrorListener($this->twig); + } + + public function testOnKernelExceptionInDevModeDoesNothing() + { + $_ENV['APP_ENV'] = 'dev'; + $kernel = $this->createMock(HttpKernelInterface::class); + $request = new Request(); + $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new \Exception()); + + $this->listener->onKernelException($event); + + $this->assertNull($event->getResponse()); + + unset($_ENV['APP_ENV']); // Cleanup + } + + public function testOnKernelExceptionJsonRequest() + { + $_ENV['APP_ENV'] = 'prod'; + $kernel = $this->createMock(HttpKernelInterface::class); + $request = new Request(); + $request->headers->set('Accept', 'application/json'); + + $exception = new NotFoundHttpException('Not found'); + $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $exception); + + $this->listener->onKernelException($event); + + $response = $event->getResponse(); + $this->assertInstanceOf(JsonResponse::class, $response); + $this->assertEquals(404, $response->getStatusCode()); + + $content = json_decode($response->getContent(), true); + $this->assertEquals('error', $content['status']); + $this->assertEquals('Resource not found', $content['message']); + + unset($_ENV['APP_ENV']); + } + + public function testOnKernelExceptionHtmlRequest() + { + $_ENV['APP_ENV'] = 'prod'; + $kernel = $this->createMock(HttpKernelInterface::class); + $request = new Request(); + + $exception = new \Exception('Error'); + $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $exception); + + $this->twig->expects($this->once()) + ->method('render') + ->with('error/500.twig', $this->anything()) + ->willReturn('Error'); + + $this->listener->onKernelException($event); + + $response = $event->getResponse(); + $this->assertInstanceOf(Response::class, $response); + $this->assertEquals(500, $response->getStatusCode()); + $this->assertEquals('Error', $response->getContent()); + + unset($_ENV['APP_ENV']); + } +} diff --git a/tests/Security/FlowAuthenticatorTest.php b/tests/Security/FlowAuthenticatorTest.php new file mode 100644 index 0000000..a416211 --- /dev/null +++ b/tests/Security/FlowAuthenticatorTest.php @@ -0,0 +1,92 @@ +urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->authenticator = new FlowAuthenticator($this->urlGenerator, $this->entityManager); + } + + public function testSupports() + { + $request = Request::create('/reservation/flow', 'POST'); + $request->attributes->set('_route', 'reservation_flow'); + + $this->assertTrue($this->authenticator->supports($request)); + } + + public function testAuthenticate() + { + $request = Request::create('/reservation/flow', 'POST', [ + '_username' => 'test@test.com', + '_password' => 'password', + '_csrf_token' => 'token' + ]); + + $session = $this->createMock(SessionInterface::class); + $request->setSession($session); + + $repository = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->with(Customer::class)->willReturn($repository); + $repository->method('findOneBy')->with(['email' => 'test@test.com'])->willReturn(new Customer()); + + $passport = $this->authenticator->authenticate($request); + + $this->assertInstanceOf(Passport::class, $passport); + $this->assertTrue($passport->hasBadge(UserBadge::class)); + } + + public function testOnAuthenticationSuccess() + { + $request = Request::create('/reservation/flow'); + $request->attributes->set('sessionId', 'session-123'); + + $token = $this->createMock(TokenInterface::class); + $customer = new Customer(); + $token->method('getUser')->willReturn($customer); + + $sessionRepo = $this->createMock(EntityRepository::class); + $orderSession = $this->createMock(OrderSession::class); + + $this->entityManager->method('getRepository')->with(OrderSession::class)->willReturn($sessionRepo); + $sessionRepo->method('findOneBy')->with(['uuid' => 'session-123'])->willReturn($orderSession); + + $orderSession->expects($this->once())->method('setCustomer')->with($customer); + $this->entityManager->expects($this->once())->method('flush'); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('reservation_flow', ['sessionId' => 'session-123']) + ->willReturn('/reservation/flow/session-123'); + + $response = $this->authenticator->onAuthenticationSuccess($request, $token, 'main'); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/reservation/flow/session-123', $response->getTargetUrl()); + } +} diff --git a/tests/Security/IntranetLockedTest.php b/tests/Security/IntranetLockedTest.php new file mode 100644 index 0000000..91449ed --- /dev/null +++ b/tests/Security/IntranetLockedTest.php @@ -0,0 +1,95 @@ +twig = $this->createMock(Environment::class); + $this->signatureClient = $this->createMock(SignatureClient::class); + $this->searchClient = $this->createMock(SearchClient::class); + $this->stripeClient = $this->createMock(StripeClient::class); + $this->mailer = $this->createMock(Mailer::class); + + $this->listener = new IntranetLocked( + $this->twig, + $this->signatureClient, + $this->searchClient, + $this->stripeClient, + $this->mailer + ); + } + + public function testOnLockedWhenEnabled() + { + $_ENV['INTRANET_LOCK'] = 'true'; + $kernel = $this->createMock(HttpKernelInterface::class); + $request = new Request(); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST); + + $this->twig->expects($this->once())->method('render')->with('security/locked.twig')->willReturn('Locked'); + + $this->listener->onLocked($event); + + $response = $event->getResponse(); + $this->assertInstanceOf(Response::class, $response); + $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode()); + + unset($_ENV['INTRANET_LOCK']); + } + + public function testOnControlAllServicesUp() + { + $kernel = $this->createMock(HttpKernelInterface::class); + $request = new Request(); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST); + + $this->signatureClient->method('status')->willReturn(true); + $this->searchClient->method('status')->willReturn(true); + $this->stripeClient->method('status')->willReturn(true); + + $this->listener->onControl($event); + + $this->assertNull($event->getResponse()); + } + + public function testOnControlServiceDown() + { + $kernel = $this->createMock(HttpKernelInterface::class); + $request = new Request(); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST); + + $this->signatureClient->method('status')->willReturn(false); + + $this->mailer->expects($this->once())->method('send'); + $this->twig->expects($this->once())->method('render')->with('security/error.twig')->willReturn('Error'); + + $this->listener->onControl($event); + + $response = $event->getResponse(); + $this->assertInstanceOf(Response::class, $response); + $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode()); + } +} diff --git a/tests/Security/KeycloakAuthenticatorTest.php b/tests/Security/KeycloakAuthenticatorTest.php new file mode 100644 index 0000000..02b0979 --- /dev/null +++ b/tests/Security/KeycloakAuthenticatorTest.php @@ -0,0 +1,86 @@ +clientRegistry = $this->createMock(ClientRegistry::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->router = $this->createMock(RouterInterface::class); + + $this->authenticator = new KeycloakAuthenticator( + $this->clientRegistry, + $this->entityManager, + $this->router + ); + } + + public function testSupports() + { + $request = Request::create('/connect/keycloak/check'); + $request->attributes->set('_route', 'connect_keycloak_check'); + + $this->assertTrue($this->authenticator->supports($request)); + } + + public function testAuthenticateExistingUser() + { + $request = Request::create('/connect/keycloak/check'); + + $client = $this->createMock(OAuth2ClientInterface::class); + $this->clientRegistry->method('getClient')->with('keycloak')->willReturn($client); + + $accessToken = new AccessToken(['access_token' => 'token']); + $client->method('getAccessToken')->willReturn($accessToken); + + // Mock Keycloak User + $keycloakUser = $this->createMock(KeycloakResourceOwner::class); + $keycloakUser->method('getId')->willReturn('keycloak-id-123'); + $keycloakUser->method('getEmail')->willReturn('user@test.com'); + $client->method('fetchUserFromToken')->willReturn($keycloakUser); + + // Mock Repository + $repository = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->with(Account::class)->willReturn($repository); + + // Existing user by Keycloak ID + $existingUser = new Account(); + $repository->method('findOneBy')->willReturnMap([ + [['keycloakId' => 'keycloak-id-123'], null, $existingUser] + ]); + + $passport = $this->authenticator->authenticate($request); + + $this->assertInstanceOf(Passport::class, $passport); + $userBadge = $passport->getBadge(UserBadge::class); + $userLoader = $userBadge->getUserLoader(); + $loadedUser = $userLoader(); + + $this->assertSame($existingUser, $loadedUser); + } +} diff --git a/tests/Security/LoginFormAuthenticatorTest.php b/tests/Security/LoginFormAuthenticatorTest.php new file mode 100644 index 0000000..36ff328 --- /dev/null +++ b/tests/Security/LoginFormAuthenticatorTest.php @@ -0,0 +1,85 @@ +entityManager = $this->createMock(EntityManagerInterface::class); + $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $this->security = $this->createMock(Security::class); + + $this->authenticator = new LoginFormAuthenticator( + $this->entityManager, + $this->urlGenerator, + $this->security + ); + } + + public function testSupports() + { + $request = Request::create('/login', 'POST'); + $request->attributes->set('_route', 'app_home'); + $request->headers->set('HOST', 'intranet.ludikevent.fr'); + + $this->assertTrue($this->authenticator->supports($request)); + } + + public function testAuthenticateUserNotFound() + { + $request = Request::create('/login', 'POST', [ + '_username' => 'unknown@test.com', + '_password' => 'pass', + '_csrf_token' => 'token' + ]); + $request->setSession($this->createMock(SessionInterface::class)); + + $repo = $this->createMock(EntityRepository::class); + $this->entityManager->method('getRepository')->willReturn($repo); + $repo->method('findOneBy')->willReturn(null); + + $this->expectException(CustomUserMessageAuthenticationException::class); + + $passport = $this->authenticator->authenticate($request); + $passport->getBadge(\Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge::class)->getUserLoader()('unknown@test.com'); + } + + public function testOnAuthenticationSuccess() + { + $request = Request::create('/login'); + $request->setSession($this->createMock(SessionInterface::class)); + $token = $this->createMock(TokenInterface::class); + + $this->urlGenerator->expects($this->once()) + ->method('generate') + ->with('app_crm') + ->willReturn('/crm'); + + $response = $this->authenticator->onAuthenticationSuccess($request, $token, 'main'); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/crm', $response->getTargetUrl()); + } +} diff --git a/tests/Security/MaintenanceListenerTest.php b/tests/Security/MaintenanceListenerTest.php new file mode 100644 index 0000000..69d9440 --- /dev/null +++ b/tests/Security/MaintenanceListenerTest.php @@ -0,0 +1,75 @@ +twig = $this->createMock(Environment::class); + $this->tempDir = sys_get_temp_dir() . '/maintenance_test_' . uniqid(); + mkdir($this->tempDir . '/var', 0777, true); + + $this->listener = new MaintenanceListener($this->twig, $this->tempDir); + } + + protected function tearDown(): void + { + $this->removeDirectory($this->tempDir); + } + + public function testOnKernelRequestMaintenanceFileExists() + { + touch($this->tempDir . '/var/.maintenance'); + + $kernel = $this->createMock(HttpKernelInterface::class); + $request = Request::create('/'); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST); + + $this->twig->expects($this->once()) + ->method('render') + ->with('security/maintenance.twig') + ->willReturn('Maintenance Mode'); + + $this->listener->onKernelRequest($event); + + $response = $event->getResponse(); + $this->assertInstanceOf(Response::class, $response); + $this->assertEquals(503, $response->getStatusCode()); + $this->assertEquals('Maintenance Mode', $response->getContent()); + } + + public function testOnKernelRequestNoMaintenanceFile() + { + $kernel = $this->createMock(HttpKernelInterface::class); + $request = Request::create('/'); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST); + + $this->listener->onKernelRequest($event); + + $this->assertNull($event->getResponse()); + } + + private function removeDirectory($dir) { + if (!is_dir($dir)) return; + $files = array_diff(scandir($dir), array('.','..')); + foreach ($files as $file) { + (is_dir("$dir/$file")) ? $this->removeDirectory("$dir/$file") : unlink("$dir/$file"); + } + rmdir($dir); + } +} diff --git a/tests/Security/PasswordGeneratorTest.php b/tests/Security/PasswordGeneratorTest.php new file mode 100644 index 0000000..c108072 --- /dev/null +++ b/tests/Security/PasswordGeneratorTest.php @@ -0,0 +1,36 @@ +generate(); + + $this->assertEquals(16, strlen($password)); + } + + public function testGenerateContainsRequiredCharacters() + { + $generator = new PasswordGenerator(12); + $password = $generator->generate(); + + $this->assertMatchesRegularExpression('/[a-z]/', $password); + $this->assertMatchesRegularExpression('/[A-Z]/', $password); + $this->assertMatchesRegularExpression('/[0-9]/', $password); + $this->assertMatchesRegularExpression('/[@#_\-]/', $password); + } + + public function testInvalidLengthThrowsException() + { + $this->expectException(\InvalidArgumentException::class); + new PasswordGenerator(3); + } +} diff --git a/tests/Security/RedirecListenerTest.php b/tests/Security/RedirecListenerTest.php new file mode 100644 index 0000000..0fbe09d --- /dev/null +++ b/tests/Security/RedirecListenerTest.php @@ -0,0 +1,76 @@ +listener = new RedirecListener(); + } + + public function testIntranetRootRedirect() + { + $kernel = $this->createMock(HttpKernelInterface::class); + $request = Request::create('/'); + $request->headers->set('HOST', 'intranet.ludikevent.fr'); + $response = new Response(); + $event = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response); + + $this->listener->onResponse($event); + + $newResponse = $event->getResponse(); + $this->assertInstanceOf(RedirectResponse::class, $newResponse); + $this->assertEquals('https://intranet.ludikevent.fr/intranet', $newResponse->getTargetUrl()); + } + + public function testReservationRedirect() + { + $kernel = $this->createMock(HttpKernelInterface::class); + $request = Request::create('/reservation/catalogue'); + $request->headers->set('HOST', 'reservation.ludikevent.fr'); + $response = new Response(); + $event = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response); + + $this->listener->onResponse($event); + + $newResponse = $event->getResponse(); + $this->assertInstanceOf(RedirectResponse::class, $newResponse); + $this->assertEquals('https://reservation.ludikevent.fr/catalogue', $newResponse->getTargetUrl()); + $this->assertEquals(Response::HTTP_MOVED_PERMANENTLY, $newResponse->getStatusCode()); + } + + public function testDevNgrokRedirect() + { + $_ENV['APP_ENV'] = 'dev'; + $listener = new RedirecListener(); // Re-instantiate to pick up dev env + + $kernel = $this->createMock(HttpKernelInterface::class); + $request = Request::create('/some/path?foo=bar'); + $request->headers->set('HOST', 'my-app.ngrok-free.app'); + $response = new Response(); + $event = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response); + + $listener->onResponse($event); + + $newResponse = $event->getResponse(); + $this->assertInstanceOf(RedirectResponse::class, $newResponse); + $this->assertEquals('https://esyweb.local/some/path?foo=bar', $newResponse->getTargetUrl()); + + $_ENV['APP_ENV'] = 'prod'; // Restore + } +} diff --git a/tests/Security/SiteMapListenerTest.php b/tests/Security/SiteMapListenerTest.php new file mode 100644 index 0000000..1963674 --- /dev/null +++ b/tests/Security/SiteMapListenerTest.php @@ -0,0 +1,79 @@ +storage = $this->createMock(StorageInterface::class); + $this->uploaderHelper = new UploaderHelper($this->storage); // Instantiate real class + + $this->optionsRepository = $this->createMock(OptionsRepository::class); + $this->productRepository = $this->createMock(ProductRepository::class); + $this->formulesRepository = $this->createMock(FormulesRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + + $this->listener = new SiteMapListener( + $this->uploaderHelper, + $this->optionsRepository, + $this->productRepository, + $this->formulesRepository, + $this->entityManager + ); + } + + public function testPopulate() + { + $urlContainer = $this->createMock(UrlContainerInterface::class); + $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $event = new SitemapPopulateEvent($urlContainer, $urlGenerator); + + $urlGenerator->method('generate')->willReturn('https://example.com/page'); + + // Mock Data + $formule = $this->createMock(Formules::class); + $formule->method('slug')->willReturn('f-1'); + $formule->method('getUpdatedAt')->willReturn(new \DateTimeImmutable()); + $this->formulesRepository->method('findBy')->willReturn([$formule]); + + // Mock UploaderHelper behavior via Storage + $this->storage->method('resolveUri')->willReturn('/images/formule.jpg'); + + $product = $this->createMock(Product::class); + $product->method('slug')->willReturn('p-1'); + $product->method('getUpdatedAt')->willReturn(new \DateTimeImmutable()); + $product->method('getName')->willReturn('Prod 1'); + $this->productRepository->method('findAll')->willReturn([$product]); + + $this->optionsRepository->method('findAll')->willReturn([]); + + $urlContainer->expects($this->atLeastOnce())->method('addUrl'); + + $this->listener->populate($event); + } +} diff --git a/tests/Security/UserCheckerTest.php b/tests/Security/UserCheckerTest.php new file mode 100644 index 0000000..93a25c4 --- /dev/null +++ b/tests/Security/UserCheckerTest.php @@ -0,0 +1,49 @@ +checker = new UserChecker(); + } + + public function testCheckPreAuthActiveUser() + { + $user = $this->createMock(Account::class); + $user->method('isActif')->willReturn(true); + + $this->checker->checkPreAuth($user); + $this->assertTrue(true); // No exception thrown + } + + public function testCheckPreAuthInactiveUserThrowsException() + { + $user = $this->createMock(Account::class); + $user->method('isActif')->willReturn(false); + + $this->expectException(CustomUserMessageAccountStatusException::class); + $this->expectExceptionMessage('Votre compte a été désactivé.'); + + $this->checker->checkPreAuth($user); + } + + public function testCheckPreAuthNonAccountUserIgnores() + { + $user = $this->createMock(UserInterface::class); + + $this->checker->checkPreAuth($user); + $this->assertTrue(true); + } +} diff --git a/tests/Service/AI/GeminiClientTest.php b/tests/Service/AI/GeminiClientTest.php new file mode 100644 index 0000000..a896c70 --- /dev/null +++ b/tests/Service/AI/GeminiClientTest.php @@ -0,0 +1,60 @@ +createStub(GenerateContentResponse::class); + $responseMock->method('text') + ->willReturn('This is a friendly update.'); + + // Mock the model + $modelMock = $this->createMock(GenerativeModel::class); + $modelMock->expects($this->once()) + ->method('generateContent') + ->with($this->isInstanceOf(TextPart::class)) + ->willReturn($responseMock); + + // Mock the client + $clientMock = $this->createMock(Client::class); + $clientMock->expects($this->once()) + ->method('withV1BetaVersion') + ->willReturnSelf(); + $clientMock->expects($this->once()) + ->method('generativeModel') + ->with('gemini-3-pro-preview') + ->willReturn($modelMock); + + // Instantiate GeminiClient with mocked Client + $geminiClient = new GeminiClient('fake-api-key', $clientMock); + + $result = $geminiClient->generateFriendlyMessage('Raw technical message'); + + $this->assertEquals('This is a friendly update.', $result); + } + + public function testGenerateFriendlyMessageException(): void + { + // Mock the client to throw an exception + $clientMock = $this->createStub(Client::class); + $clientMock->method('withV1BetaVersion') + ->willThrowException(new \Exception('API Error')); + + // Instantiate GeminiClient with mocked Client + $geminiClient = new GeminiClient('fake-api-key', $clientMock); + + $result = $geminiClient->generateFriendlyMessage('Raw technical message'); + + $this->assertNull($result); + } +} diff --git a/tests/Service/Generator/TempPasswordGeneratorTest.php b/tests/Service/Generator/TempPasswordGeneratorTest.php new file mode 100644 index 0000000..e38131a --- /dev/null +++ b/tests/Service/Generator/TempPasswordGeneratorTest.php @@ -0,0 +1,73 @@ +assertEquals(12, strlen($password)); + } + + public function testGenerateCustomLength(): void + { + $length = 16; + $password = TempPasswordGenerator::generate($length); + $this->assertEquals($length, strlen($password)); + } + + public function testGenerateInvalidLength(): void + { + $password = TempPasswordGenerator::generate(-5); + $this->assertEquals(12, strlen($password)); // Should fallback to default + } + + public function testGenerateCustomCharacters(): void + { + $chars = 'ABC'; + $password = TempPasswordGenerator::generate(10, $chars); + $this->assertEquals(10, strlen($password)); + $this->assertMatchesRegularExpression('/^[ABC]+$/', $password); + } + + public function testIsComplexValid(): void + { + // Needs 8+ chars, Upper, Lower, Digit, Special + $password = 'Ab1!defg'; + $this->assertTrue(TempPasswordGenerator::isComplex($password)); + } + + public function testIsComplexTooShort(): void + { + $password = 'Ab1!de'; // 6 chars + $this->assertFalse(TempPasswordGenerator::isComplex($password)); + } + + public function testIsComplexMissingUpper(): void + { + $password = 'ab1!defg'; + $this->assertFalse(TempPasswordGenerator::isComplex($password)); + } + + public function testIsComplexMissingLower(): void + { + $password = 'AB1!DEFG'; + $this->assertFalse(TempPasswordGenerator::isComplex($password)); + } + + public function testIsComplexMissingDigit(): void + { + $password = 'Abc!defg'; + $this->assertFalse(TempPasswordGenerator::isComplex($password)); + } + + public function testIsComplexMissingSpecial(): void + { + $password = 'Ab12defg'; + $this->assertFalse(TempPasswordGenerator::isComplex($password)); + } +} diff --git a/tests/Service/Mailer/Event/CreatedAdminEventTest.php b/tests/Service/Mailer/Event/CreatedAdminEventTest.php new file mode 100644 index 0000000..cc9c590 --- /dev/null +++ b/tests/Service/Mailer/Event/CreatedAdminEventTest.php @@ -0,0 +1,21 @@ +assertSame($account, $event->getAccount()); + $this->assertSame($password, $event->getPassword()); + } +} diff --git a/tests/Service/Mailer/MailerSubscriberTest.php b/tests/Service/Mailer/MailerSubscriberTest.php new file mode 100644 index 0000000..e7fc945 --- /dev/null +++ b/tests/Service/Mailer/MailerSubscriberTest.php @@ -0,0 +1,50 @@ +createMock(UrlGeneratorInterface::class); + $mailer = $this->createMock(Mailer::class); + + $subscriber = new MailerSubscriber($urlGenerator, $mailer); + + $account = $this->createStub(Account::class); + $account->method('getEmail')->willReturn('test@example.com'); + $account->method('getUsername')->willReturn('testuser'); + + $password = 'secret'; + + $event = new CreatedAdminEvent($account, $password); + + $urlGenerator->expects($this->once()) + ->method('generate') + ->with('app_home') + ->willReturn('http://example.com/home'); + + $mailer->expects($this->once()) + ->method('send') + ->with( + 'test@example.com', + 'testuser', + "[LudikEvent] - Création d'un compte administrateur", + "mails/new_admin.twig", + [ + 'username' => 'testuser', + 'password' => 'secret', + 'url' => 'http://example.com/home', + ] + ); + + $subscriber->onAdminEvent($event); + } +} diff --git a/tests/Service/Mailer/MailerTest.php b/tests/Service/Mailer/MailerTest.php new file mode 100644 index 0000000..d9e254e --- /dev/null +++ b/tests/Service/Mailer/MailerTest.php @@ -0,0 +1,62 @@ +createMock(MailerInterface::class); + $entityManager = $this->createStub(EntityManagerInterface::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); + $profiler = $this->createStub(Profiler::class); + $twig = $this->createMock(Environment::class); + + $mailer = new Mailer( + $symfonyMailer, + $entityManager, + $urlGenerator, + $profiler, + $twig + ); + + $template = 'mails/test.twig'; + $data = ['foo' => 'bar']; + + // Mock Twig rendering + // 1. First call for MJML content + // 2. Second call for Text content (fallback) + $twig->expects($this->exactly(2)) + ->method('render') + ->willReturnCallback(function ($tpl, $ctx) use ($template) { + if ($tpl === $template) { + return 'Hello'; + } + if ($tpl === 'txt-' . $template) { + return 'Hello Text'; + } + return ''; + }); + + $symfonyMailer->expects($this->once()) + ->method('send') + ->with($this->isInstanceOf(Email::class)); + + $mailer->send( + 'dest@example.com', + 'Dest Name', + 'Subject', + $template, + $data + ); + } +} diff --git a/tests/Service/Media/VideoThumbnailerTest.php b/tests/Service/Media/VideoThumbnailerTest.php new file mode 100644 index 0000000..6bd6baf --- /dev/null +++ b/tests/Service/Media/VideoThumbnailerTest.php @@ -0,0 +1,20 @@ +expectException(\RuntimeException::class); + + $thumbnailer->generateThumbnail('non_existent_video_file.mp4', 'output_thumb.jpg'); + } +} diff --git a/tests/Service/Pdf/ContratPdfServiceTest.php b/tests/Service/Pdf/ContratPdfServiceTest.php new file mode 100644 index 0000000..20a91f1 --- /dev/null +++ b/tests/Service/Pdf/ContratPdfServiceTest.php @@ -0,0 +1,59 @@ +createStub(KernelInterface::class); + $kernel->method('getProjectDir')->willReturn(sys_get_temp_dir()); + + // Create dummy favicon for logo check + $faviconDir = sys_get_temp_dir() . '/public/provider/images'; + if (!is_dir($faviconDir)) { + mkdir($faviconDir, 0777, true); + } + $pngData = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); + file_put_contents($faviconDir . '/favicon.png', $pngData); + + $contrat = $this->createStub(Contrats::class); + $customer = $this->createStub(Customer::class); + + $contrat->method('getNumReservation')->willReturn('RES-123'); + $contrat->method('getCustomer')->willReturn($customer); + $contrat->method('getAddressEvent')->willReturn('123 Event St'); + $contrat->method('getZipCodeEvent')->willReturn('75000'); + $contrat->method('getTownEvent')->willReturn('Paris'); + $contrat->method('getDateAt')->willReturn(new \DateTimeImmutable('2023-01-01')); + $contrat->method('getEndAt')->willReturn(new \DateTimeImmutable('2023-01-02')); // 2 days + $contrat->method('getContratsLines')->willReturn(new ArrayCollection([])); + $contrat->method('getContratsOptions')->willReturn(new ArrayCollection([])); + + // Mock nullable strings + $contrat->method('getTypeSol')->willReturn('Herbe'); + $contrat->method('getDistancePower')->willReturn(10.0); + $contrat->method('getPente')->willReturn('Plat'); + $contrat->method('getAccess')->willReturn('Facile'); + $contrat->method('getAddress2Event')->willReturn(null); + $contrat->method('getAddress3Event')->willReturn(null); + + $customer->method('getName')->willReturn('Doe'); + $customer->method('getSurname')->willReturn('John'); + $customer->method('getPhone')->willReturn('0102030405'); + $customer->method('getEmail')->willReturn('john@example.com'); + + $pdfService = new ContratPdfService($kernel, $contrat); + $content = $pdfService->generate(); + + $this->assertNotEmpty($content); + $this->assertStringStartsWith('%PDF', $content); + } +} diff --git a/tests/Service/Pdf/DevisPdfServiceTest.php b/tests/Service/Pdf/DevisPdfServiceTest.php new file mode 100644 index 0000000..7d6e863 --- /dev/null +++ b/tests/Service/Pdf/DevisPdfServiceTest.php @@ -0,0 +1,50 @@ +createStub(KernelInterface::class); + $kernel->method('getProjectDir')->willReturn(sys_get_temp_dir()); + + // Create dummy favicon for logo check + $faviconDir = sys_get_temp_dir() . '/public/provider/images'; + if (!is_dir($faviconDir)) { + mkdir($faviconDir, 0777, true); + } + $pngData = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); + file_put_contents($faviconDir . '/favicon.png', $pngData); + + $devis = $this->createStub(Devis::class); + $productRepository = $this->createStub(ProductRepository::class); + $customer = $this->createStub(Customer::class); + + $devis->method('getNum')->willReturn('DEV-001'); + $devis->method('getCustomer')->willReturn($customer); + $devis->method('getBillAddress')->willReturn(null); // Simplify + $devis->method('getAddressShip')->willReturn(null); + $devis->method('getStartAt')->willReturn(new \DateTimeImmutable('2023-01-01')); + $devis->method('getEndAt')->willReturn(new \DateTimeImmutable('2023-01-02')); + $devis->method('getDevisLines')->willReturn(new ArrayCollection([])); + $devis->method('getDevisOptions')->willReturn(new ArrayCollection([])); + + $customer->method('getName')->willReturn('Client SAS'); + $customer->method('getEmail')->willReturn('client@example.com'); + + $pdfService = new DevisPdfService($kernel, $devis, $productRepository); + $content = $pdfService->generate(); + + $this->assertNotEmpty($content); + $this->assertStringStartsWith('%PDF', $content); + } +} diff --git a/tests/Service/Pdf/PlPdfTest.php b/tests/Service/Pdf/PlPdfTest.php new file mode 100644 index 0000000..3566adc --- /dev/null +++ b/tests/Service/Pdf/PlPdfTest.php @@ -0,0 +1,49 @@ +createStub(KernelInterface::class); + $kernel->method('getProjectDir')->willReturn(sys_get_temp_dir()); + + // Create dummy favicon for logo check + $faviconDir = sys_get_temp_dir() . '/public/provider/images'; + if (!is_dir($faviconDir)) { + mkdir($faviconDir, 0777, true); + } + $pngData = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); + file_put_contents($faviconDir . '/favicon.png', $pngData); + + $contrat = $this->createStub(Contrats::class); + $contratsPayments = $this->createStub(ContratsPayments::class); + $customer = $this->createStub(Customer::class); + + $contrat->method('getNumReservation')->willReturn('RES-123'); + $contrat->method('getCustomer')->willReturn($customer); + + $customer->method('getSurname')->willReturn('John'); + $customer->method('getName')->willReturn('Doe'); + $customer->method('getEmail')->willReturn('john@example.com'); + + $contratsPayments->method('getAmount')->willReturn(100.0); + $contratsPayments->method('getValidateAt')->willReturn(new \DateTimeImmutable('2023-01-01 12:00:00')); + $contratsPayments->method('getCard')->willReturn(['type' => 'Carte Bancaire']); + $contratsPayments->method('getPaymentId')->willReturn('TX-999'); + + $pdfService = new PlPdf($kernel, $contratsPayments, $contrat); + $content = $pdfService->generate(); + + $this->assertNotEmpty($content); + $this->assertStringStartsWith('%PDF', $content); + } +} diff --git a/tests/Service/ResetPassword/Event/ResetPasswordConfirmEventTest.php b/tests/Service/ResetPassword/Event/ResetPasswordConfirmEventTest.php new file mode 100644 index 0000000..9559cd4 --- /dev/null +++ b/tests/Service/ResetPassword/Event/ResetPasswordConfirmEventTest.php @@ -0,0 +1,17 @@ +setPassword($password); + $this->assertEquals($password, $event->getPassword()); + } +} diff --git a/tests/Service/ResetPassword/Event/ResetPasswordEventTest.php b/tests/Service/ResetPassword/Event/ResetPasswordEventTest.php new file mode 100644 index 0000000..837eae2 --- /dev/null +++ b/tests/Service/ResetPassword/Event/ResetPasswordEventTest.php @@ -0,0 +1,17 @@ +setEmail($email); + $this->assertEquals($email, $event->getEmail()); + } +} diff --git a/tests/Service/ResetPassword/ResetPasswordSubscriberTest.php b/tests/Service/ResetPassword/ResetPasswordSubscriberTest.php new file mode 100644 index 0000000..c86e4f3 --- /dev/null +++ b/tests/Service/ResetPassword/ResetPasswordSubscriberTest.php @@ -0,0 +1,76 @@ +createStub(UrlGeneratorInterface::class); + $entityManager = $this->createStub(EntityManagerInterface::class); + $mailer = $this->createMock(Mailer::class); + $requestStack = $this->createStub(RequestStack::class); + + $subscriber = new ResetPasswordSubscriber($urlGenerator, $entityManager, $mailer, $requestStack); + + $event = new ResetPasswordEvent(); + $event->setEmail('unknown@example.com'); + + $repo = $this->createStub(EntityRepository::class); + $entityManager->method('getRepository')->with(Account::class)->willReturn($repo); + $repo->method('findOneBy')->with(['email' => 'unknown@example.com'])->willReturn(null); + + $mailer->expects($this->never())->method('send'); + + $subscriber->onResetPassword($event); + } + + public function testOnResetPasswordSuccess(): void + { + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + $mailer = $this->createMock(Mailer::class); + $requestStack = $this->createStub(RequestStack::class); + + $subscriber = new ResetPasswordSubscriber($urlGenerator, $entityManager, $mailer, $requestStack); + + $event = new ResetPasswordEvent(); + $event->setEmail('user@example.com'); + + $account = $this->createStub(Account::class); + $account->method('getEmail')->willReturn('user@example.com'); + $account->method('getUsername')->willReturn('user'); + $account->method('getId')->willReturn(1); + + $repoAccount = $this->createStub(EntityRepository::class); + $repoRequest = $this->createStub(EntityRepository::class); + + $entityManager->method('getRepository')->willReturnMap([ + [Account::class, $repoAccount], + [AccountResetPasswordRequest::class, $repoRequest], + ]); + + $repoAccount->method('findOneBy')->with(['email' => 'user@example.com'])->willReturn($account); + $repoRequest->method('findOneBy')->with(['Account' => $account])->willReturn(null); + + $entityManager->expects($this->once())->method('persist')->with($this->isInstanceOf(AccountResetPasswordRequest::class)); + $entityManager->expects($this->once())->method('flush'); + + $urlGenerator->method('generate')->willReturn('http://reset-link'); + + $mailer->expects($this->once())->method('send'); + + $subscriber->onResetPassword($event); + } +} diff --git a/tests/Service/Search/ClientTest.php b/tests/Service/Search/ClientTest.php new file mode 100644 index 0000000..e8add53 --- /dev/null +++ b/tests/Service/Search/ClientTest.php @@ -0,0 +1,39 @@ +createStub(MeilisearchClient::class); + $msClient->method('health')->willReturn(['status' => 'available']); + + $client = new Client($msClient); + $this->assertTrue($client->status()); + } + + public function testSearch(): void + { + $msClient = $this->createStub(MeilisearchClient::class); + $indexMock = $this->createStub(Indexes::class); + + $msClient->method('index')->willReturn($indexMock); + + // Mock SearchResult + $searchResult = $this->createStub(SearchResult::class); + $searchResult->method('toArray')->willReturn(['hits' => []]); + $indexMock->method('search')->willReturn($searchResult); + + $client = new Client($msClient); + $result = $client->search('product', 'query'); + + $this->assertIsArray($result); + } +} diff --git a/tests/Service/Signature/ClientTest.php b/tests/Service/Signature/ClientTest.php new file mode 100644 index 0000000..e484ecd --- /dev/null +++ b/tests/Service/Signature/ClientTest.php @@ -0,0 +1,75 @@ +createStub(RequestStack::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); + $entityManager = $this->createStub(EntityManagerInterface::class); + $kernel = $this->createStub(KernelInterface::class); + $storage = $this->createStub(StorageInterface::class); + + $docuseal = $this->createStub(\Docuseal\Api::class); + $docuseal->method('listTemplates')->willReturn([]); + + $client = new Client($requestStack, $urlGenerator, $entityManager, $kernel, $storage, $docuseal); + + $this->assertTrue($client->status()); + } + + public function testCreateSubmissionContrat(): void + { + $requestStack = $this->createStub(RequestStack::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); + $entityManager = $this->createStub(EntityManagerInterface::class); + $kernel = $this->createStub(KernelInterface::class); + $storage = $this->createStub(StorageInterface::class); + $docuseal = $this->createStub(\Docuseal\Api::class); + + $kernel->method('getProjectDir')->willReturn(sys_get_temp_dir()); + + $client = new Client($requestStack, $urlGenerator, $entityManager, $kernel, $storage, $docuseal); + + $contrat = $this->createMock(Contrats::class); + $customer = $this->createStub(Customer::class); + + $contrat->method('getCustomer')->willReturn($customer); + $contrat->method('getNumReservation')->willReturn('RES-123'); + $contrat->method('getId')->willReturn(1); + + $customer->method('getEmail')->willReturn('test@example.com'); + $customer->method('getName')->willReturn('Doe'); + $customer->method('getSurname')->willReturn('John'); + + $docuseal->method('createSubmissionFromPdf')->willReturn([ + 'submitters' => [ + 1 => ['id' => 'sub_123'] + ] + ]); + + $docuseal->method('getSubmitter')->with('sub_123')->willReturn(['slug' => 'slug_123']); + + $contrat->expects($this->exactly(2)) + ->method('getSignID') + ->willReturnOnConsecutiveCalls(null, 'sub_123'); + + $contrat->expects($this->once())->method('setSignID')->with('sub_123'); + + $link = $client->createSubmissionContrat($contrat); + + $this->assertStringContainsString('/s/slug_123', $link); + } +} diff --git a/tests/Service/Stripe/ClientTest.php b/tests/Service/Stripe/ClientTest.php new file mode 100644 index 0000000..747dff5 --- /dev/null +++ b/tests/Service/Stripe/ClientTest.php @@ -0,0 +1,37 @@ +createStub(EntityManagerInterface::class); + + $storage = $this->createStub(StorageInterface::class); + $uploaderHelper = new UploaderHelper($storage); + + $stripeClient = $this->createStub(StripeClient::class); + + $accountService = $this->createStub(AccountService::class); + $accountService->method('all')->willReturn(new \Stripe\Collection()); + + $stripeClient->method('__get')->willReturnMap([ + ['accounts', $accountService] + ]); + + $client = new Client($em, $uploaderHelper, $stripeClient); + + $result = $client->check(); + + $this->assertTrue($result['state']); + } +} diff --git a/tests/Service/System/DatabaseDumperTest.php b/tests/Service/System/DatabaseDumperTest.php new file mode 100644 index 0000000..bbecf70 --- /dev/null +++ b/tests/Service/System/DatabaseDumperTest.php @@ -0,0 +1,26 @@ +lastCommand = $command; + $returnCode = 0; + } + }; + + $dumper->dump('postgresql://user:pass@localhost:5432/db', 'dump.sql'); + + $this->assertStringContainsString('pg_dump', $dumper->lastCommand); + } +} diff --git a/tests/Service/System/GitClientTest.php b/tests/Service/System/GitClientTest.php new file mode 100644 index 0000000..6acadb4 --- /dev/null +++ b/tests/Service/System/GitClientTest.php @@ -0,0 +1,21 @@ +getLastCommitInfo('.'); + + $this->assertIsArray($info); + $this->assertArrayHasKey('message', $info); + $this->assertArrayHasKey('date', $info); + $this->assertArrayHasKey('hash', $info); + } +} diff --git a/tests/Service/System/ZipArchiverTest.php b/tests/Service/System/ZipArchiverTest.php new file mode 100644 index 0000000..0004a6e --- /dev/null +++ b/tests/Service/System/ZipArchiverTest.php @@ -0,0 +1,39 @@ +createArchive($zipPath, $sqlPath, ['files' => $tmpDir]); + + $this->assertFileExists($zipPath); + + // Check content + $zip = new \ZipArchive(); + $zip->open($zipPath); + $this->assertNotFalse($zip->getFromName('database.sql')); + $this->assertNotFalse($zip->getFromName('files/file.txt')); // Might be slightly different path depending on recursive iterator + $zip->close(); + + // Cleanup + unlink($zipPath); + unlink($sqlPath); + unlink($tmpDir . '/file.txt'); + rmdir($tmpDir); + } +} diff --git a/tests/Twig/StripeExtensionTest.php b/tests/Twig/StripeExtensionTest.php new file mode 100644 index 0000000..fd66801 --- /dev/null +++ b/tests/Twig/StripeExtensionTest.php @@ -0,0 +1,69 @@ +createStub(StorageInterface::class); + $uploaderHelper = new UploaderHelper($storage); + + $signatureClient = $this->createStub(SignatureClient::class); + $stripeClient = $this->createStub(StripeClientService::class); + $em = $this->createStub(EntityManagerInterface::class); + + $extension = new StripeExtension($uploaderHelper, $signatureClient, $stripeClient, $em); + + $this->assertIsArray($extension->getFilters()); + $this->assertIsArray($extension->getFunctions()); + } + + public function testTotalQuoto(): void + { + $storage = $this->createStub(StorageInterface::class); + $uploaderHelper = new UploaderHelper($storage); + $signatureClient = $this->createStub(SignatureClient::class); + $stripeClient = $this->createStub(StripeClientService::class); + $em = $this->createStub(EntityManagerInterface::class); + + $extension = new StripeExtension($uploaderHelper, $signatureClient, $stripeClient, $em); + + $devis = $this->createStub(Devis::class); + $devis->method('getDevisLines')->willReturn(new \Doctrine\Common\Collections\ArrayCollection([])); + $devis->method('getDevisOptions')->willReturn(new \Doctrine\Common\Collections\ArrayCollection([])); + + $total = $extension->totalQuoto($devis); + $this->assertIsFloat($total); + } + + public function testTotalContrat(): void + { + $storage = $this->createStub(StorageInterface::class); + $uploaderHelper = new UploaderHelper($storage); + $signatureClient = $this->createStub(SignatureClient::class); + $stripeClient = $this->createStub(StripeClientService::class); + $em = $this->createStub(EntityManagerInterface::class); + + $extension = new StripeExtension($uploaderHelper, $signatureClient, $stripeClient, $em); + + $contrat = $this->createStub(Contrats::class); + $contrat->method('getContratsLines')->willReturn(new \Doctrine\Common\Collections\ArrayCollection([])); + $contrat->method('getContratsOptions')->willReturn(new \Doctrine\Common\Collections\ArrayCollection([])); + $contrat->method('getDateAt')->willReturn(new \DateTimeImmutable()); + $contrat->method('getEndAt')->willReturn(new \DateTimeImmutable()); + + $total = $extension->totalContrat($contrat); + $this->assertIsFloat($total); + } +} diff --git a/tests/Twig/ViteAssetExtensionTest.php b/tests/Twig/ViteAssetExtensionTest.php new file mode 100644 index 0000000..0dde4a7 --- /dev/null +++ b/tests/Twig/ViteAssetExtensionTest.php @@ -0,0 +1,57 @@ +createStub(CacheItemPoolInterface::class); + + $extension = new class('/path/to/manifest.json', $cache, null) extends ViteAssetExtension { + protected function getNonce(): string { + return 'nonce123'; + } + }; + + $html = $extension->asset('app.js'); + $this->assertStringContainsString('http://localhost:5173', $html); + $this->assertStringContainsString('nonce="nonce123"', $html); + } + + public function testAssetProd(): void + { + $_ENV['VITE_LOAD'] = "1"; + + $cache = $this->createStub(CacheItemPoolInterface::class); + $item = $this->createStub(CacheItemInterface::class); + $item->method('isHit')->willReturn(false); + $item->method('set')->willReturn($item); + + $cache->method('getItem')->willReturn($item); + + $manifestPath = sys_get_temp_dir() . '/manifest.json'; + file_put_contents($manifestPath, json_encode([ + 'app.js' => ['file' => 'app.123.js', 'css' => ['app.123.css']] + ])); + + $extension = new class($manifestPath, $cache, null) extends ViteAssetExtension { + protected function getNonce(): string { + return 'nonce123'; + } + }; + + $html = $extension->asset('app.js'); + $this->assertStringContainsString('/build/app.123.js', $html); + $this->assertStringContainsString('/build/app.123.css', $html); + + unlink($manifestPath); + } +} \ No newline at end of file