diff --git a/.github/jobs/baseinstall.sh b/.github/jobs/baseinstall.sh index 719f065608..143b94d5ad 100755 --- a/.github/jobs/baseinstall.sh +++ b/.github/jobs/baseinstall.sh @@ -4,7 +4,7 @@ export version="$1" db=${2:-install} -phpversion="${3:-8.1}" +phpversion="${3:-8.2}" # If this script is called from unit-tests.sh, we use the test environment export APP_ENV="${4:-prod}" diff --git a/.github/jobs/composer_setup.sh b/.github/jobs/composer_setup.sh index 15187b3bfe..a9ec2e7eb5 100755 --- a/.github/jobs/composer_setup.sh +++ b/.github/jobs/composer_setup.sh @@ -8,6 +8,7 @@ section_start "Configure PHP" PHPVERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION."\n";') export PHPVERSION echo "$PHPVERSION" | tee -a "$ARTIFACTS"/phpversion.txt +sudo apt-get -y purge "php$PHPVERSION-redis" section_end section_start "Run composer" diff --git a/.github/jobs/data/codespellignorefiles.txt b/.github/jobs/data/codespellignorefiles.txt index 310e0c3c4d..0f848b7ad6 100644 --- a/.github/jobs/data/codespellignorefiles.txt +++ b/.github/jobs/data/codespellignorefiles.txt @@ -27,3 +27,4 @@ composer* ./doc/logos ./m4 ./webapp/tests/Unit/Fixtures +./webapp/config/reference.php diff --git a/.github/jobs/detect_dump.sh b/.github/jobs/detect_dump.sh index d72ed3c092..f353dc5d24 100755 --- a/.github/jobs/detect_dump.sh +++ b/.github/jobs/detect_dump.sh @@ -8,6 +8,7 @@ OUT=$(find ./ -name ".git*" -type d -prune -o \ -name "bundles" -prune -o \ -name "cache" -type d -prune -o \ -name "ace" -type d -prune -o \ + -path "./webapp/config/reference.php" -prune -o \ -type f -print0 | xargs -0 grep --color "dump(" | grep -v "Yaml::dump(") || true # Show detected debug statements diff --git a/.github/jobs/syntax-check b/.github/jobs/syntax-check index 1c6460cc29..a4384d6f7f 100755 --- a/.github/jobs/syntax-check +++ b/.github/jobs/syntax-check @@ -25,14 +25,14 @@ if [ ! -x /usr/bin/shellcheck ]; then fi find . \( \ - -path ./webapp/vendor -prune \ - -o -path ./webapp/var -prune \ - -o -path ./output -prune \ - -o -path ./.git -prune \ - -o -path ./webapp/migrations -prune \ - -o -path ./example_problems -prune \ - -o -type f \) \ - -a -type f | \ + -path ./webapp/vendor -prune \ + -o -path ./webapp/var -prune \ + -o -path ./output -prune \ + -o -path ./.git -prune \ + -o -path ./webapp/migrations -prune \ + -o -path ./example_problems -prune \ + -o -path ./webapp/config/reference.php \ + -o -type f -print \) | \ while read -r i ; do if [[ "$i" == *\.php ]] || grep -q "^#\\!.*php" "$i" && \ echo "$i" | grep -qvE '(^\./(webapp/resources/adminer)\.php)'; then diff --git a/.github/jobs/unit-tests.sh b/.github/jobs/unit-tests.sh index 3357a7868b..89a395dd29 100755 --- a/.github/jobs/unit-tests.sh +++ b/.github/jobs/unit-tests.sh @@ -8,7 +8,7 @@ DIR="$PWD" export version=$1 unittest=$2 -[ "$version" = "8.1" ] && CODECOVERAGE=1 || CODECOVERAGE=0 +[ "$version" = "8.2" ] && CODECOVERAGE=1 || CODECOVERAGE=0 # Set up export unit=1 @@ -46,7 +46,7 @@ cp ${DIR}/webapp/var/log/*.log "$ARTIFACTS"/ set -e CNT=0 -THRESHOLD=2 +THRESHOLD=10 if [ $CODECOVERAGE -eq 1 ]; then CNT=$(sed -n '/Generating code coverage report/,$p' "$ARTIFACTS"/phpunit.out | grep -cv ^$) fi diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 0dbddf8f72..73cf358c57 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -46,7 +46,7 @@ jobs: image: pipelinecomponents/php-codesniffer:latest strategy: matrix: - PHPVERSION: ["8.1", "8.2", "8.3", "8.4"] + PHPVERSION: ["8.2", "8.3", "8.4"] steps: - run: apk add git - uses: actions/checkout@v4 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index d6d53f8712..023328165e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -43,7 +43,7 @@ jobs: options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3 strategy: matrix: - PHPVERSION: [8.1, 8.4] + PHPVERSION: [8.2, 8.4] TEST: [Unit, E2E] steps: - uses: actions/checkout@v4 diff --git a/webapp/composer.json b/webapp/composer.json index 3a41ef7621..4defb3181d 100644 --- a/webapp/composer.json +++ b/webapp/composer.json @@ -39,7 +39,7 @@ } ], "require": { - "php": "^8.1.0", + "php": "^8.2.0", "ext-bcmath": "*", "ext-ctype": "*", "ext-curl": "*", @@ -57,7 +57,7 @@ "doctrine/doctrine-bundle": "^2.8", "doctrine/doctrine-fixtures-bundle": "^4.0", "doctrine/doctrine-migrations-bundle": "^3.2", - "doctrine/orm": "^2.14", + "doctrine/orm": "^3.0", "enshrined/svg-sanitize": "^0.22.0", "friendsofsymfony/rest-bundle": "^3.5", "ircmaxell/password-compat": "*", @@ -72,32 +72,32 @@ "ramsey/uuid": "^4.2", "riverline/multipart-parser": "^2.1", "sentry/sentry-symfony": "^5.0", - "symfony/asset": "6.4.*", - "symfony/browser-kit": "6.4.*", - "symfony/console": "6.4.*", - "symfony/css-selector": "6.4.*", - "symfony/dotenv": "6.4.*", - "symfony/expression-language": "6.4.*", + "symfony/asset": "7.4.*", + "symfony/browser-kit": "7.4.*", + "symfony/console": "7.4.*", + "symfony/css-selector": "7.4.*", + "symfony/dotenv": "7.4.*", + "symfony/expression-language": "7.4.*", "symfony/flex": "^2", - "symfony/form": "6.4.*", - "symfony/framework-bundle": "6.4.*", - "symfony/html-sanitizer": "6.4.*", - "symfony/http-client": "6.4.*", - "symfony/intl": "6.4.*", - "symfony/mime": "6.4.*", + "symfony/form": "7.4.*", + "symfony/framework-bundle": "7.4.*", + "symfony/html-sanitizer": "7.4.*", + "symfony/http-client": "7.4.*", + "symfony/intl": "7.4.*", + "symfony/mime": "7.4.*", "symfony/monolog-bundle": "^3.8.0", - "symfony/property-access": "6.4.*", - "symfony/property-info": "6.4.*", - "symfony/runtime": "6.4.*", - "symfony/security-bundle": "6.4.*", - "symfony/security-csrf": "6.4.*", - "symfony/serializer": "6.4.*", - "symfony/stopwatch": "6.4.*", - "symfony/translation": "6.4.*", - "symfony/twig-bundle": "6.4.*", - "symfony/validator": "6.4.*", - "symfony/web-profiler-bundle": "6.4.*", - "symfony/yaml": "6.4.*", + "symfony/property-access": "7.4.*", + "symfony/property-info": "7.4.*", + "symfony/runtime": "7.4.*", + "symfony/security-bundle": "7.4.*", + "symfony/security-csrf": "7.4.*", + "symfony/serializer": "7.4.*", + "symfony/stopwatch": "7.4.*", + "symfony/translation": "7.4.*", + "symfony/twig-bundle": "7.4.*", + "symfony/validator": "7.4.*", + "symfony/web-profiler-bundle": "7.4.*", + "symfony/yaml": "7.4.*", "twig/extra-bundle": "^3.5", "twig/markdown-extra": "^3.5", "twig/string-extra": "^3.5", @@ -112,10 +112,10 @@ "phpunit/phpunit": "^9.6", "sebastian/diff": "*", "squizlabs/php_codesniffer": "*", - "symfony/debug-bundle": "6.4.*", + "symfony/debug-bundle": "7.4.*", "symfony/maker-bundle": "^1.42", - "symfony/phpunit-bridge": "6.4.*", - "symfony/var-dumper": "6.4.*" + "symfony/phpunit-bridge": "7.4.*", + "symfony/var-dumper": "7.4.*" }, "autoload": { "psr-4": { @@ -136,7 +136,7 @@ }, "sort-packages": true, "platform": { - "php": "8.1.0" + "php": "8.2.0" }, "allow-plugins": { "composer/package-versions-deprecated": true, @@ -172,7 +172,7 @@ "extra": { "symfony": { "allow-contrib": true, - "require": "6.4.*" + "require": "7.4.*" } } } diff --git a/webapp/composer.lock b/webapp/composer.lock index 9b8a1d628a..aeac5e748e 100644 --- a/webapp/composer.lock +++ b/webapp/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": "acf8aab5dc3598efb723d47096cbcf51", + "content-hash": "fc2a7ce40ff2320da1bf87e3922d59aa", "packages": [ { "name": "brick/math", @@ -141,100 +141,6 @@ }, "time": "2024-07-08T12:26:09+00:00" }, - { - "name": "doctrine/cache", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.2.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", - "type": "tidelift" - } - ], - "abandoned": true, - "time": "2022-05-20T20:07:39+00:00" - }, { "name": "doctrine/collections", "version": "2.4.0", @@ -321,97 +227,6 @@ ], "time": "2025-10-25T09:18:13+00:00" }, - { - "name": "doctrine/common", - "version": "3.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/common.git", - "reference": "d9ea4a54ca2586db781f0265d36bea731ac66ec5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/d9ea4a54ca2586db781f0265d36bea731ac66ec5", - "reference": "d9ea4a54ca2586db781f0265d36bea731ac66ec5", - "shasum": "" - }, - "require": { - "doctrine/persistence": "^2.0 || ^3.0 || ^4.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9.0 || ^10.0", - "doctrine/collections": "^1", - "phpstan/phpstan": "^1.4.1", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", - "squizlabs/php_codesniffer": "^3.0", - "symfony/phpunit-bridge": "^6.1", - "vimeo/psalm": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", - "homepage": "https://www.doctrine-project.org/projects/common.html", - "keywords": [ - "common", - "doctrine", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/common/issues", - "source": "https://github.com/doctrine/common/tree/3.5.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon", - "type": "tidelift" - } - ], - "time": "2025-01-01T22:12:03+00:00" - }, { "name": "doctrine/data-fixtures", "version": "2.2.0", @@ -497,48 +312,40 @@ }, { "name": "doctrine/dbal", - "version": "3.10.3", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "65edaca19a752730f290ec2fb89d593cb40afb43" + "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/65edaca19a752730f290ec2fb89d593cb40afb43", - "reference": "65edaca19a752730f290ec2fb89d593cb40afb43", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc", + "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc", "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", - "symfony/console": "^4.4|^5.4|^6.0|^7.0" + "symfony/cache": "^6.3.8|^7.0", + "symfony/console": "^5.4|^6.3|^7.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": { @@ -591,7 +398,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.10.3" + "source": "https://github.com/doctrine/dbal/tree/4.3.4" }, "funding": [ { @@ -607,7 +414,7 @@ "type": "tidelift" } ], - "time": "2025-10-09T09:05:12+00:00" + "time": "2025-10-09T09:11:36+00:00" }, { "name": "doctrine/deprecations", @@ -1382,61 +1189,49 @@ }, { "name": "doctrine/orm", - "version": "2.20.8", + "version": "3.5.7", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "5bff0919a78c86238536a9b5396024fe3603b5d1" + "reference": "f18de9d569f00ed6eb9dac4b33c7844d705d17da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/5bff0919a78c86238536a9b5396024fe3603b5d1", - "reference": "5bff0919a78c86238536a9b5396024fe3603b5d1", + "url": "https://api.github.com/repos/doctrine/orm/zipball/f18de9d569f00ed6eb9dac4b33c7844d705d17da", + "reference": "f18de9d569f00ed6eb9dac4b33c7844d705d17da", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/cache": "^1.12.1 || ^2.1.1", - "doctrine/collections": "^1.5 || ^2.1", - "doctrine/common": "^3.0.3", - "doctrine/dbal": "^2.13.1 || ^3.2", + "doctrine/collections": "^2.2", + "doctrine/dbal": "^3.8.2 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^2 || ^3", - "doctrine/persistence": "^2.4 || ^3", + "doctrine/lexer": "^3", + "doctrine/persistence": "^3.3.1 || ^4", "ext-ctype": "*", - "php": "^7.1 || ^8.0", + "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/polyfill-php72": "^1.23", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "doctrine/annotations": "<1.13 || >= 3.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/var-exporter": "^6.3.9 || ^7.0" }, "require-dev": { - "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^14.0", - "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/extension-installer": "~1.1.0 || ^1.4", - "phpstan/phpstan": "~1.4.10 || 2.1.23", - "phpstan/phpstan-deprecation-rules": "^1 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "doctrine/coding-standard": "^14.0", + "phpbench/phpbench": "^1.0", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "2.1.23", + "phpstan/phpstan-deprecation-rules": "^2", + "phpunit/phpunit": "^10.5.0 || ^11.5", "psr/log": "^1 || ^2 || ^3", - "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" + "symfony/cache": "^5.4 || ^6.2 || ^7.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", - "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" }, - "bin": [ - "bin/doctrine" - ], "type": "library", "autoload": { "psr-4": { @@ -1477,40 +1272,37 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.20.8" + "source": "https://github.com/doctrine/orm/tree/3.5.7" }, - "time": "2025-11-10T13:35:45+00:00" + "time": "2025-11-11T18:27:40+00:00" }, { "name": "doctrine/persistence", - "version": "3.4.3", + "version": "4.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "d59e6ef7caffe6a30f4b6f9e9079a75f52c64ae0" + "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/d59e6ef7caffe6a30f4b6f9e9079a75f52c64ae0", - "reference": "d59e6ef7caffe6a30f4b6f9e9079a75f52c64ae0", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", + "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", "shasum": "" }, "require": { "doctrine/event-manager": "^1 || ^2", - "php": "^7.2 || ^8.0", + "php": "^8.1", "psr/cache": "^1.0 || ^2.0 || ^3.0" }, - "conflict": { - "doctrine/common": "<2.10" - }, "require-dev": { - "doctrine/coding-standard": "^12 || ^14", - "doctrine/common": "^3.0", - "phpstan/phpstan": "^1 || 2.1.30", - "phpstan/phpstan-phpunit": "^1 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8.5.38 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0" + "doctrine/coding-standard": "^14", + "phpstan/phpstan": "2.1.30", + "phpstan/phpstan-phpunit": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.58 || ^12", + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0" }, "type": "library", "autoload": { @@ -1559,7 +1351,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.4.3" + "source": "https://github.com/doctrine/persistence/tree/4.1.1" }, "funding": [ { @@ -1575,7 +1367,7 @@ "type": "tidelift" } ], - "time": "2025-10-21T15:21:39+00:00" + "time": "2025-10-16T20:13:18+00:00" }, { "name": "doctrine/sql-formatter", @@ -4459,28 +4251,28 @@ }, { "name": "symfony/asset", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "cfee7c0d64be113383db74a2fdd65d426b7f3aab" + "reference": "0f7bccb9ffa1f373cbd659774d90629b2773464f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/cfee7c0d64be113383db74a2fdd65d426b7f3aab", - "reference": "cfee7c0d64be113383db74a2fdd65d426b7f3aab", + "url": "https://api.github.com/repos/symfony/asset/zipball/0f7bccb9ffa1f373cbd659774d90629b2773464f", + "reference": "0f7bccb9ffa1f373cbd659774d90629b2773464f", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/http-foundation": "<5.4" + "symfony/http-foundation": "<6.4" }, "require-dev": { - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0" + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4508,7 +4300,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/v6.4.24" + "source": "https://github.com/symfony/asset/tree/v7.4.0" }, "funding": [ { @@ -4528,31 +4320,32 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "symfony/browser-kit", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "067e301786bbb58048077fc10507aceb18226e23" + "reference": "3bb26dafce31633b1f699894c86379eefc8af5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/067e301786bbb58048077fc10507aceb18226e23", - "reference": "067e301786bbb58048077fc10507aceb18226e23", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/3bb26dafce31633b1f699894c86379eefc8af5bb", + "reference": "3bb26dafce31633b1f699894c86379eefc8af5bb", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/dom-crawler": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/dom-crawler": "^6.4|^7.0|^8.0" }, "require-dev": { - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0" + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4580,7 +4373,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/v6.4.28" + "source": "https://github.com/symfony/browser-kit/tree/v7.4.0" }, "funding": [ { @@ -4600,35 +4393,38 @@ "type": "tidelift" } ], - "time": "2025-10-16T22:35:35+00:00" + "time": "2025-11-05T14:29:59+00:00" }, { "name": "symfony/cache", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "31628f36fc97c5714d181b3a8d29efb85c6a7677" + "reference": "a7a1325a5de2e54ddb45fda002ff528162e48293" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/31628f36fc97c5714d181b3a8d29efb85c6a7677", - "reference": "31628f36fc97c5714d181b3a8d29efb85c6a7677", + "url": "https://api.github.com/repos/symfony/cache/zipball/a7a1325a5de2e54ddb45fda002ff528162e48293", + "reference": "a7a1325a5de2e54ddb45fda002ff528162e48293", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^2.5|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.3.6|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "conflict": { - "doctrine/dbal": "<2.13.1", - "symfony/dependency-injection": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/var-dumper": "<5.4" + "doctrine/dbal": "<3.6", + "ext-redis": "<6.1", + "ext-relay": "<0.12.1", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" }, "provide": { "psr/cache-implementation": "2.0|3.0", @@ -4637,15 +4433,16 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4680,7 +4477,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.28" + "source": "https://github.com/symfony/cache/tree/v7.4.0" }, "funding": [ { @@ -4700,7 +4497,7 @@ "type": "tidelift" } ], - "time": "2025-10-30T08:37:02+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/cache-contracts", @@ -4780,20 +4577,20 @@ }, { "name": "symfony/clock", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8" + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", - "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/clock": "^1.0", "symfony/polyfill-php83": "^1.28" }, @@ -4834,7 +4631,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.4.24" + "source": "https://github.com/symfony/clock/tree/v7.4.0" }, "funding": [ { @@ -4854,38 +4651,38 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/config", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "15947c18ef3ddb0b2f4ec936b9e90e2520979f62" + "reference": "f76c74e93bce2b9285f2dad7fbd06fa8182a7a41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/15947c18ef3ddb0b2f4ec936b9e90e2520979f62", - "reference": "15947c18ef3ddb0b2f4ec936b9e90e2520979f62", + "url": "https://api.github.com/repos/symfony/config/zipball/f76c74e93bce2b9285f2dad7fbd06fa8182a7a41", + "reference": "f76c74e93bce2b9285f2dad7fbd06fa8182a7a41", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^7.1|^8.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<5.4", + "symfony/finder": "<6.4", "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4913,7 +4710,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/v6.4.28" + "source": "https://github.com/symfony/config/tree/v7.4.0" }, "funding": [ { @@ -4933,51 +4730,51 @@ "type": "tidelift" } ], - "time": "2025-11-01T19:52:02+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/console", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "13d3176cf8ad8ced24202844e9f95af11e2959fc" + "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/13d3176cf8ad8ced24202844e9f95af11e2959fc", - "reference": "13d3176cf8ad8ced24202844e9f95af11e2959fc", + "url": "https://api.github.com/repos/symfony/console/zipball/0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", + "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" + "symfony/string": "^7.2|^8.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5011,7 +4808,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.27" + "source": "https://github.com/symfony/console/tree/v7.4.0" }, "funding": [ { @@ -5031,24 +4828,24 @@ "type": "tidelift" } ], - "time": "2025-10-06T10:25:16+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "9b784413143701aa3c94ac1869a159a9e53e8761" + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/9b784413143701aa3c94ac1869a159a9e53e8761", - "reference": "9b784413143701aa3c94ac1869a159a9e53e8761", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab862f478513e7ca2fe9ec117a6f01a8da6e1135", + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -5080,7 +4877,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.24" + "source": "https://github.com/symfony/css-selector/tree/v7.4.0" }, "funding": [ { @@ -5100,44 +4897,43 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-10-30T13:39:42+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "5f311eaf0b321f8ec640f6bae12da43a14026898" + "reference": "3972ca7bbd649467b21a54870721b9e9f3652f9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5f311eaf0b321f8ec640f6bae12da43a14026898", - "reference": "5f311eaf0b321f8ec640f6bae12da43a14026898", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3972ca7bbd649467b21a54870721b9e9f3652f9b", + "reference": "3972ca7bbd649467b21a54870721b9e9f3652f9b", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4.20|^7.2.5" + "symfony/service-contracts": "^3.6", + "symfony/var-exporter": "^6.4.20|^7.2.5|^8.0" }, "conflict": { "ext-psr": "<1.1|>=2", - "symfony/config": "<6.1", - "symfony/finder": "<5.4", - "symfony/proxy-manager-bridge": "<6.3", - "symfony/yaml": "<5.4" + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" }, "provide": { "psr/container-implementation": "1.1|2.0", "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^6.1|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5165,7 +4961,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/v6.4.26" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.0" }, "funding": [ { @@ -5185,7 +4981,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5256,67 +5052,68 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "c14bb5a9125c411e73354954940e06b6e7fcc344" + "reference": "7b511891a81ca14e993b6c88fd35d6bf656085f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/c14bb5a9125c411e73354954940e06b6e7fcc344", - "reference": "c14bb5a9125c411e73354954940e06b6e7fcc344", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/7b511891a81ca14e993b6c88fd35d6bf656085f7", + "reference": "7b511891a81ca14e993b6c88fd35d6bf656085f7", "shasum": "" }, "require": { - "doctrine/event-manager": "^1.2|^2", - "doctrine/persistence": "^2.5|^3.1|^4", - "php": ">=8.1", + "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", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "doctrine/dbal": "<2.13.1", + "doctrine/collections": "<1.8", + "doctrine/dbal": "<3.6", "doctrine/lexer": "<1.1", "doctrine/orm": "<2.15", - "symfony/cache": "<5.4", - "symfony/dependency-injection": "<6.2", - "symfony/form": "<5.4.38|>=6,<6.4.6|>=7,<7.0.6", - "symfony/http-foundation": "<6.3", - "symfony/http-kernel": "<6.2", - "symfony/lock": "<6.3", - "symfony/messenger": "<5.4", - "symfony/property-info": "<5.4", - "symfony/security-bundle": "<5.4", + "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" + "symfony/validator": "<7.4" }, "require-dev": { - "doctrine/collections": "^1.0|^2.0", + "doctrine/collections": "^1.8|^2.0", "doctrine/data-fixtures": "^1.1|^2", - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "doctrine/orm": "^2.15|^3", "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^6.2|^7.0", - "symfony/doctrine-messenger": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4.38|^6.4.6|^7.0.6", - "symfony/http-kernel": "^6.3|^7.0", - "symfony/lock": "^6.3|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/proxy-manager-bridge": "^6.4", - "symfony/security-core": "^6.4|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/doctrine-messenger": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^7.2|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^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/security-core": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/type-info": "^7.1.8|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -5344,7 +5141,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.26" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.4.0" }, "funding": [ { @@ -5364,30 +5161,31 @@ "type": "tidelift" } ], - "time": "2025-09-26T15:07:38+00:00" + "time": "2025-11-04T03:05:49+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.4.25", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "976302990f9f2a6d4c07206836dd4ca77cae9524" + "reference": "8f3e7464fe7e77294686e935956a6a8ccf7442c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/976302990f9f2a6d4c07206836dd4ca77cae9524", - "reference": "976302990f9f2a6d4c07206836dd4ca77cae9524", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/8f3e7464fe7e77294686e935956a6a8ccf7442c4", + "reference": "8f3e7464fe7e77294686e935956a6a8ccf7442c4", "shasum": "" }, "require": { "masterminds/html5": "^2.6", - "php": ">=8.1", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/css-selector": "^5.4|^6.0|^7.0" + "symfony/css-selector": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5415,7 +5213,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.25" + "source": "https://github.com/symfony/dom-crawler/tree/v7.4.0" }, "funding": [ { @@ -5435,32 +5233,32 @@ "type": "tidelift" } ], - "time": "2025-08-05T18:56:08+00:00" + "time": "2025-10-31T09:30:03+00:00" }, { "name": "symfony/dotenv", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff" + "reference": "1658a4d34df028f3d93bcdd8e81f04423925a364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/234b6c602f12b00693f4b0d1054386fb30dfc8ff", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/1658a4d34df028f3d93bcdd8e81f04423925a364", + "reference": "1658a4d34df028f3d93bcdd8e81f04423925a364", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/console": "<5.4", - "symfony/process": "<5.4" + "symfony/console": "<6.4", + "symfony/process": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5493,7 +5291,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.24" + "source": "https://github.com/symfony/dotenv/tree/v7.4.0" }, "funding": [ { @@ -5513,35 +5311,38 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "41bedcaec5b72640b0ec2096547b75fda72ead6c" + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/41bedcaec5b72640b0ec2096547b75fda72ead6c", - "reference": "41bedcaec5b72640b0ec2096547b75fda72ead6c", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/48be2b0653594eea32dcef130cca1c811dcf25c2", + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "conflict": { "symfony/deprecation-contracts": "<2.5", "symfony/http-kernel": "<6.4" }, "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^5.4|^6.0|^7.0" + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ "Resources/bin/patch-type-declarations" @@ -5572,7 +5373,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/v6.4.26" + "source": "https://github.com/symfony/error-handler/tree/v7.4.0" }, "funding": [ { @@ -5592,28 +5393,28 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-11-05T14:29:59+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.25", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b0cf3162020603587363f0551cd3be43958611ff" + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", - "reference": "b0cf3162020603587363f0551cd3be43958611ff", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9dddcddff1ef974ad87b3708e4b442dc38b2261d", + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<5.4", + "symfony/dependency-injection": "<6.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -5622,13 +5423,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5656,7 +5458,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/v6.4.25" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.0" }, "funding": [ { @@ -5676,7 +5478,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2025-10-28T09:38:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5756,21 +5558,21 @@ }, { "name": "symfony/expression-language", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "1ea0adaa53539ea7e70821ae9de49ebe03ae7091" + "reference": "8b9bbbb8c71f79a09638f6ea77c531e511139efa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/1ea0adaa53539ea7e70821ae9de49ebe03ae7091", - "reference": "1ea0adaa53539ea7e70821ae9de49ebe03ae7091", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/8b9bbbb8c71f79a09638f6ea77c531e511139efa", + "reference": "8b9bbbb8c71f79a09638f6ea77c531e511139efa", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/cache": "^5.4|^6.0|^7.0", + "php": ">=8.2", + "symfony/cache": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, @@ -5800,7 +5602,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.4.24" + "source": "https://github.com/symfony/expression-language/tree/v7.4.0" }, "funding": [ { @@ -5820,29 +5622,29 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" + "reference": "d551b38811096d0be9c4691d406991b47c0c630a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", + "reference": "d551b38811096d0be9c4691d406991b47c0c630a", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^5.4|^6.4|^7.0" + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5870,7 +5672,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.24" + "source": "https://github.com/symfony/filesystem/tree/v7.4.0" }, "funding": [ { @@ -5890,27 +5692,27 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/finder", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b" + "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a1b6aa435d2fba50793b994a839c32b6064f063b", - "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b", + "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", + "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.0|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5938,7 +5740,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.27" + "source": "https://github.com/symfony/finder/tree/v7.4.0" }, "funding": [ { @@ -5958,7 +5760,7 @@ "type": "tidelift" } ], - "time": "2025-10-15T18:32:00+00:00" + "time": "2025-11-05T05:42:40+00:00" }, { "name": "symfony/flex", @@ -6035,56 +5837,58 @@ }, { "name": "symfony/form", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "5d922aea68ffe1637535713b35b29f6f34b7d81c" + "reference": "00b8d61709b323749aef317950abd276f309597b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/5d922aea68ffe1637535713b35b29f6f34b7d81c", - "reference": "5d922aea68ffe1637535713b35b29f6f34b7d81c", + "url": "https://api.github.com/repos/symfony/form/zipball/00b8d61709b323749aef317950abd276f309597b", + "reference": "00b8d61709b323749aef317950abd276f309597b", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/options-resolver": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/options-resolver": "^7.3|^8.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-access": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<5.4", - "symfony/dependency-injection": "<5.4", - "symfony/doctrine-bridge": "<5.4.21|>=6,<6.2.7", - "symfony/error-handler": "<5.4", - "symfony/framework-bundle": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", + "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/intl": "<7.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<6.3" + "symfony/twig-bridge": "<6.4" }, "require-dev": { "doctrine/collections": "^1.0|^2.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/html-sanitizer": "^6.1|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.2|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/clock": "^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/expression-language": "^6.4|^7.0|^8.0", + "symfony/html-sanitizer": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4.3|^7.0.3|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4.12|^7.1.5|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6112,7 +5916,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.4.27" + "source": "https://github.com/symfony/form/tree/v7.4.0" }, "funding": [ { @@ -6132,112 +5936,117 @@ "type": "tidelift" } ], - "time": "2025-10-10T09:11:15+00:00" + "time": "2025-11-20T12:20:24+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "ee58c2a73218d8f4763824e1414c5f9b4519c91f" + "reference": "3c62a3437267ac55bcd40175689c74772250e943" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/ee58c2a73218d8f4763824e1414c5f9b4519c91f", - "reference": "ee58c2a73218d8f4763824e1414c5f9b4519c91f", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3c62a3437267ac55bcd40175689c74772250e943", + "reference": "3c62a3437267ac55bcd40175689c74772250e943", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.1", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.4.12|^7.0", + "php": ">=8.2", + "symfony/cache": "^6.4.12|^7.0|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.1|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4", + "symfony/error-handler": "^7.3|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^7.1|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/routing": "^7.4|^8.0" }, "conflict": { - "doctrine/annotations": "<1.13.1", "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/asset": "<5.4", + "symfony/asset": "<6.4", "symfony/asset-mapper": "<6.4", - "symfony/clock": "<6.3", - "symfony/console": "<5.4|>=7.0", + "symfony/clock": "<6.4", + "symfony/console": "<6.4", "symfony/dom-crawler": "<6.4", - "symfony/dotenv": "<5.4", - "symfony/form": "<5.4", - "symfony/http-client": "<6.3", - "symfony/lock": "<5.4", - "symfony/mailer": "<5.4", - "symfony/messenger": "<6.3", + "symfony/dotenv": "<6.4", + "symfony/form": "<7.4", + "symfony/http-client": "<6.4", + "symfony/lock": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<7.4", "symfony/mime": "<6.4", - "symfony/property-access": "<5.4", - "symfony/property-info": "<5.4", - "symfony/runtime": "<5.4.45|>=6.0,<6.4.13|>=7.0,<7.1.6", + "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": "<5.4", - "symfony/security-csrf": "<5.4", - "symfony/serializer": "<6.4", - "symfony/stopwatch": "<5.4", - "symfony/translation": "<6.4", - "symfony/twig-bridge": "<5.4", - "symfony/twig-bundle": "<5.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/workflow": "<6.4" + "symfony/webhook": "<7.2", + "symfony/workflow": "<7.4" }, "require-dev": { - "doctrine/annotations": "^1.13.1|^2", "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "seld/jsonlint": "^1.10", - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/asset-mapper": "^6.4|^7.0", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/clock": "^6.2|^7.0", - "symfony/console": "^5.4.9|^6.0.9|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/dotenv": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/html-sanitizer": "^6.1|^7.0", - "symfony/http-client": "^6.3|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/mailer": "^5.4|^6.0|^7.0", - "symfony/messenger": "^6.3|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/notifier": "^5.4|^6.0|^7.0", + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/asset-mapper": "^6.4|^7.0|^8.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/dotenv": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/html-sanitizer": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/json-streamer": "^7.3|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/mailer": "^6.4|^7.0|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/notifier": "^6.4|^7.0|^8.0", + "symfony/object-mapper": "^7.3|^8.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0", - "symfony/scheduler": "^6.4.4|^7.0.4", - "symfony/security-bundle": "^5.4|^6.0|^7.0", - "symfony/semaphore": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/string": "^5.4|^6.0|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/twig-bundle": "^5.4|^6.0|^7.0", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/web-link": "^5.4|^6.0|^7.0", - "symfony/workflow": "^6.4|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0", - "twig/twig": "^2.10|^3.0.4" + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0", + "symfony/scheduler": "^6.4.4|^7.0.4|^8.0", + "symfony/security-bundle": "^6.4|^7.0|^8.0", + "symfony/semaphore": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.2.5|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/translation": "^7.3|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "symfony/type-info": "^7.1.8|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/web-link": "^6.4|^7.0|^8.0", + "symfony/webhook": "^7.2|^8.0", + "symfony/workflow": "^7.4|^8.0", + "symfony/yaml": "^7.3|^8.0", + "twig/twig": "^3.12" }, "type": "symfony-bundle", "autoload": { @@ -6265,7 +6074,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.27" + "source": "https://github.com/symfony/framework-bundle/tree/v7.4.0" }, "funding": [ { @@ -6285,27 +6094,28 @@ "type": "tidelift" } ], - "time": "2025-10-15T17:35:09+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/html-sanitizer", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/html-sanitizer.git", - "reference": "03f9c2eed8ca49f027bd9a54d25c3b9efea35525" + "reference": "5b0bbcc3600030b535dd0b17a0e8c56243f96d7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/03f9c2eed8ca49f027bd9a54d25c3b9efea35525", - "reference": "03f9c2eed8ca49f027bd9a54d25c3b9efea35525", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/5b0bbcc3600030b535dd0b17a0e8c56243f96d7f", + "reference": "5b0bbcc3600030b535dd0b17a0e8c56243f96d7f", "shasum": "" }, "require": { "ext-dom": "*", "league/uri": "^6.5|^7.0", "masterminds/html5": "^2.7.2", - "php": ">=8.1" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -6338,7 +6148,7 @@ "sanitizer" ], "support": { - "source": "https://github.com/symfony/html-sanitizer/tree/v6.4.28" + "source": "https://github.com/symfony/html-sanitizer/tree/v7.4.0" }, "funding": [ { @@ -6358,24 +6168,24 @@ "type": "tidelift" } ], - "time": "2025-10-29T09:25:59+00:00" + "time": "2025-10-30T13:39:42+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "c9e69c185c4a845f9d46958cdb0dc7aa847f3981" + "reference": "ee5e0e0139ab506f6063a230e631bed677c650a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/c9e69c185c4a845f9d46958cdb0dc7aa847f3981", - "reference": "c9e69c185c4a845f9d46958cdb0dc7aa847f3981", + "url": "https://api.github.com/repos/symfony/http-client/zipball/ee5e0e0139ab506f6063a230e631bed677c650a4", + "reference": "ee5e0e0139ab506f6063a230e631bed677c650a4", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "~3.4.4|^3.5.2", @@ -6383,8 +6193,10 @@ "symfony/service-contracts": "^2.5|^3" }, "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.3" + "symfony/http-foundation": "<6.4" }, "provide": { "php-http/async-client-implementation": "*", @@ -6393,19 +6205,20 @@ "symfony/http-client-implementation": "3.0" }, "require-dev": { - "amphp/amp": "^2.5", - "amphp/http-client": "^4.2.1", - "amphp/http-tunnel": "^1.0", - "amphp/socket": "^1.1", + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^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/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6436,7 +6249,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.28" + "source": "https://github.com/symfony/http-client/tree/v7.4.0" }, "funding": [ { @@ -6456,7 +6269,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T17:39:22+00:00" + "time": "2025-11-20T12:32:50+00:00" }, { "name": "symfony/http-client-contracts", @@ -6538,36 +6351,37 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.29", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88" + "reference": "769c1720b68e964b13b58529c17d4a385c62167b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b03d11e015552a315714c127d8d1e0f9e970ec88", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/769c1720b68e964b13b58529c17d4a385c62167b", + "reference": "769c1720b68e964b13b58529c17d4a385c62167b", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { + "doctrine/dbal": "<3.6", "symfony/cache": "<6.4.12|>=7.0,<7.1.5" }, "require-dev": { - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6595,7 +6409,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.29" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.0" }, "funding": [ { @@ -6615,77 +6429,78 @@ "type": "tidelift" } ], - "time": "2025-11-08T16:40:12+00:00" + "time": "2025-11-13T08:49:24+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.29", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "18818b48f54c1d2bd92b41d82d8345af50b15658" + "reference": "7348193cd384495a755554382e4526f27c456085" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/18818b48f54c1d2bd92b41d82d8345af50b15658", - "reference": "18818b48f54c1d2bd92b41d82d8345af50b15658", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/7348193cd384495a755554382e4526f27c456085", + "reference": "7348193cd384495a755554382e4526f27c456085", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/browser-kit": "<5.4", - "symfony/cache": "<5.4", - "symfony/config": "<6.1", - "symfony/console": "<5.4", + "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": "<5.4", - "symfony/form": "<5.4", - "symfony/http-client": "<5.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", - "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/translation": "<5.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<5.4", + "symfony/twig-bridge": "<6.4", "symfony/validator": "<6.4", - "symfony/var-dumper": "<6.3", - "twig/twig": "<2.13" + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/clock": "^6.2|^7.0", - "symfony/config": "^6.1|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4.5|^6.0.5|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4.4|^7.0.4", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.4|^7.0", - "symfony/var-exporter": "^6.2|^7.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" }, "type": "library", "autoload": { @@ -6713,7 +6528,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.29" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.0" }, "funding": [ { @@ -6733,29 +6548,32 @@ "type": "tidelift" } ], - "time": "2025-11-12T11:22:59+00:00" + "time": "2025-11-27T13:38:24+00:00" }, { "name": "symfony/intl", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "ccc52824610e7de72424cf516e52d4fb39e3bfa5" + "reference": "2fa074de6c7faa6b54f2891fc22708f42245ed5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/ccc52824610e7de72424cf516e52d4fb39e3bfa5", - "reference": "ccc52824610e7de72424cf516e52d4fb39e3bfa5", + "url": "https://api.github.com/repos/symfony/intl/zipball/2fa074de6c7faa6b54f2891fc22708f42245ed5c", + "reference": "2fa074de6c7faa6b54f2891fc22708f42245ed5c", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/string": "<7.1" }, "require-dev": { - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6800,7 +6618,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v6.4.27" + "source": "https://github.com/symfony/intl/tree/v7.4.0" }, "funding": [ { @@ -6820,24 +6638,24 @@ "type": "tidelift" } ], - "time": "2025-10-01T06:01:44+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/mime", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "61ab9681cdfe315071eb4fa79b6ad6ab030a9235" + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/61ab9681cdfe315071eb4fa79b6ad6ab030a9235", - "reference": "61ab9681cdfe315071eb4fa79b6ad6ab030a9235", + "url": "https://api.github.com/repos/symfony/mime/zipball/bdb02729471be5d047a3ac4a69068748f1a6be7a", + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" @@ -6846,18 +6664,18 @@ "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<5.4", + "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "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": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.4|^7.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^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/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -6889,7 +6707,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.26" + "source": "https://github.com/symfony/mime/tree/v7.4.0" }, "funding": [ { @@ -6909,42 +6727,42 @@ "type": "tidelift" } ], - "time": "2025-09-16T08:22:30+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "d2f4b68e3247cf44d93f48545c8c072a75c17e5b" + "reference": "189d16466ff83d9c51fad26382bf0beeb41bda21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/d2f4b68e3247cf44d93f48545c8c072a75c17e5b", - "reference": "d2f4b68e3247cf44d93f48545c8c072a75c17e5b", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/189d16466ff83d9c51fad26382bf0beeb41bda21", + "reference": "189d16466ff83d9c51fad26382bf0beeb41bda21", "shasum": "" }, "require": { - "monolog/monolog": "^1.25.1|^2|^3", - "php": ">=8.1", + "monolog/monolog": "^3", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<5.4", - "symfony/http-foundation": "<5.4", - "symfony/security-core": "<5.4" + "symfony/console": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/security-core": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/mailer": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/security-core": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/mailer": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -6972,7 +6790,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.28" + "source": "https://github.com/symfony/monolog-bridge/tree/v7.4.0" }, "funding": [ { @@ -6992,48 +6810,43 @@ "type": "tidelift" } ], - "time": "2025-10-30T19:57:08+00:00" + "time": "2025-11-01T09:17:33+00:00" }, { "name": "symfony/monolog-bundle", - "version": "v3.10.0", + "version": "v3.11.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181" + "reference": "e12eb92655b234cd50c21cda648088847a7ec777" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", - "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e12eb92655b234cd50c21cda648088847a7ec777", + "reference": "e12eb92655b234cd50c21cda648088847a7ec777", "shasum": "" }, "require": { + "composer-runtime-api": "^2.0", "monolog/monolog": "^1.25.1 || ^2.0 || ^3.0", - "php": ">=7.2.5", - "symfony/config": "^5.4 || ^6.0 || ^7.0", - "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", - "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", - "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.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", + "symfony/polyfill-php84": "^1.30" }, "require-dev": { - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/phpunit-bridge": "^6.3 || ^7.0", - "symfony/yaml": "^5.4 || ^6.0 || ^7.0" + "symfony/console": "^6.4 || ^7.0", + "symfony/phpunit-bridge": "^7.3.3", + "symfony/yaml": "^6.4 || ^7.0" }, "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "autoload": { "psr-4": { - "Symfony\\Bundle\\MonologBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Bundle\\MonologBundle\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -7057,7 +6870,7 @@ ], "support": { "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.10.0" + "source": "https://github.com/symfony/monolog-bundle/tree/v3.11.0" }, "funding": [ { @@ -7068,29 +6881,33 @@ "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": "2023-11-06T17:08:13+00:00" + "time": "2025-11-27T09:16:19+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.4.25", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe" + "reference": "b38026df55197f9e39a44f3215788edf83187b80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28e7e2db8a73e9511df892d36445f61314bbebe", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -7124,7 +6941,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.25" + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" }, "funding": [ { @@ -7144,31 +6961,31 @@ "type": "tidelift" } ], - "time": "2025-08-04T17:06:28+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557" + "reference": "aa075ce6f54fe931f03c1e382597912f4fd94e1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/dcab5ac87450aaed26483ba49c2ce86808da7557", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/aa075ce6f54fe931f03c1e382597912f4fd94e1e", + "reference": "aa075ce6f54fe931f03c1e382597912f4fd94e1e", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/security-core": "<5.4" + "symfony/security-core": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/security-core": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7200,7 +7017,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.24" + "source": "https://github.com/symfony/password-hasher/tree/v7.4.0" }, "funding": [ { @@ -7220,7 +7037,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-13T16:46:49+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -7650,34 +7467,49 @@ "time": "2024-12-23T08:48:59+00:00" }, { - "name": "symfony/polyfill-php72", - "version": "v1.31.0", + "name": "symfony/polyfill-php80", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", - "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { "php": ">=7.2" }, - "type": "metapackage", + "type": "library", "extra": { "thanks": { "url": "https://github.com/symfony/polyfill", "name": "symfony/polyfill" } }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -7687,7 +7519,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -7696,7 +7528,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -7707,25 +7539,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { - "name": "symfony/polyfill-php80", + "name": "symfony/polyfill-php83", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -7743,7 +7579,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Polyfill\\Php83\\": "" }, "classmap": [ "Resources/stubs" @@ -7754,10 +7590,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -7767,7 +7599,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -7776,7 +7608,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -7796,20 +7628,20 @@ "type": "tidelift" } ], - "time": "2025-01-02T08:10:11+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { - "name": "symfony/polyfill-php83", + "name": "symfony/polyfill-php84", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", "shasum": "" }, "require": { @@ -7827,7 +7659,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" + "Symfony\\Polyfill\\Php84\\": "" }, "classmap": [ "Resources/stubs" @@ -7847,7 +7679,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -7856,7 +7688,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" }, "funding": [ { @@ -7876,20 +7708,20 @@ "type": "tidelift" } ], - "time": "2025-07-08T02:45:35+00:00" + "time": "2025-06-24T13:30:11+00:00" }, { - "name": "symfony/polyfill-php84", + "name": "symfony/polyfill-php85", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", "shasum": "" }, "require": { @@ -7907,7 +7739,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php84\\": "" + "Symfony\\Polyfill\\Php85\\": "" }, "classmap": [ "Resources/stubs" @@ -7927,7 +7759,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -7936,7 +7768,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" }, "funding": [ { @@ -7956,29 +7788,29 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2025-06-23T16:12:55+00:00" }, { "name": "symfony/property-access", - "version": "v6.4.25", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168" + "reference": "537626149d2910ca43eb9ce465654366bf4442f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fedc771326d4978a7d3167fa009a509b06a2e168", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168", + "url": "https://api.github.com/repos/symfony/property-access/zipball/537626149d2910ca43eb9ce465654366bf4442f4", + "reference": "537626149d2910ca43eb9ce465654366bf4442f4", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/property-info": "^6.4|^7.0|^8.0" }, "require-dev": { - "symfony/cache": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4.1|^7.0.1|^8.0" }, "type": "library", "autoload": { @@ -8017,7 +7849,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.25" + "source": "https://github.com/symfony/property-access/tree/v7.4.0" }, "funding": [ { @@ -8037,41 +7869,41 @@ "type": "tidelift" } ], - "time": "2025-08-12T15:42:57+00:00" + "time": "2025-09-08T21:14:32+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6" + "reference": "c3c686e3d3a33a99f6967e69d6d5832acb7c25a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/1056ae3621eeddd78d7c5ec074f1c1784324eec6", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6", + "url": "https://api.github.com/repos/symfony/property-info/zipball/c3c686e3d3a33a99f6967e69d6d5832acb7c25a1", + "reference": "c3c686e3d3a33a99f6967e69d6d5832acb7c25a1", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/string": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/type-info": "^7.3.5|^8.0" }, "conflict": { - "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<5.2", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/cache": "<5.4", - "symfony/dependency-injection": "<5.4|>=6.0,<6.4", - "symfony/serializer": "<5.4" + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^5.2", "phpstan/phpdoc-parser": "^1.0|^2.0", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/serializer": "^5.4|^6.4|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8107,7 +7939,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.24" + "source": "https://github.com/symfony/property-info/tree/v7.4.0" }, "funding": [ { @@ -8127,40 +7959,41 @@ "type": "tidelift" } ], - "time": "2025-07-14T16:38:25+00:00" + "time": "2025-11-13T08:38:49+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "6954b4e8aef0e5d46f8558c90edcf27bb01b4724" + "reference": "0101ff8bd0506703b045b1670960302d302a726c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/6954b4e8aef0e5d46f8558c90edcf27bb01b4724", - "reference": "6954b4e8aef0e5d46f8558c90edcf27bb01b4724", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/0101ff8bd0506703b045b1670960302d302a726c", + "reference": "0101ff8bd0506703b045b1670960302d302a726c", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/http-message": "^1.0|^2.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0" + "symfony/http-foundation": "^6.4|^7.0|^8.0" }, "conflict": { "php-http/discovery": "<1.15", - "symfony/http-kernel": "<6.2" + "symfony/http-kernel": "<6.4" }, "require-dev": { "nyholm/psr7": "^1.1", "php-http/discovery": "^1.15", "psr/log": "^1.1.4|^2|^3", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^6.2|^7.0", - "symfony/http-kernel": "^6.2|^7.0" + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -8194,7 +8027,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v6.4.24" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.4.0" }, "funding": [ { @@ -8214,40 +8047,38 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-13T08:38:49+00:00" }, { "name": "symfony/routing", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "ae064a6d9cf39507f9797658465a2ca702965fa8" + "reference": "4720254cb2644a0b876233d258a32bf017330db7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/ae064a6d9cf39507f9797658465a2ca702965fa8", - "reference": "ae064a6d9cf39507f9797658465a2ca702965fa8", + "url": "https://api.github.com/repos/symfony/routing/zipball/4720254cb2644a0b876233d258a32bf017330db7", + "reference": "4720254cb2644a0b876233d258a32bf017330db7", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "doctrine/annotations": "<1.12", - "symfony/config": "<6.2", - "symfony/dependency-injection": "<5.4", - "symfony/yaml": "<5.4" + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^6.2|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8281,7 +8112,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.28" + "source": "https://github.com/symfony/routing/tree/v7.4.0" }, "funding": [ { @@ -8301,35 +8132,35 @@ "type": "tidelift" } ], - "time": "2025-10-31T16:43:05+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/runtime", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "59933ca737fd60fad548241b6d879cd0e4be31ab" + "reference": "e3dd6c0f46a6810b3245726e8452cee45754e628" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/59933ca737fd60fad548241b6d879cd0e4be31ab", - "reference": "59933ca737fd60fad548241b6d879cd0e4be31ab", + "url": "https://api.github.com/repos/symfony/runtime/zipball/e3dd6c0f46a6810b3245726e8452cee45754e628", + "reference": "e3dd6c0f46a6810b3245726e8452cee45754e628", "shasum": "" }, "require": { "composer-plugin-api": "^1.0|^2.0", - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/dotenv": "<5.4" + "symfony/dotenv": "<6.4" }, "require-dev": { - "composer/composer": "^1.0.2|^2.0", - "symfony/console": "^5.4.9|^6.0.9|^7.0", - "symfony/dotenv": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0" + "composer/composer": "^2.6", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dotenv": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, "type": "composer-plugin", "extra": { @@ -8364,7 +8195,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v6.4.26" + "source": "https://github.com/symfony/runtime/tree/v7.4.0" }, "funding": [ { @@ -8384,75 +8215,71 @@ "type": "tidelift" } ], - "time": "2025-09-11T15:30:54+00:00" + "time": "2025-11-04T03:05:49+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "b83773107a5b83a5507df9e88bd50d495f6e8b72" + "reference": "48a64e746857464a5e8fd7bab84b31c9ba967eb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/b83773107a5b83a5507df9e88bd50d495f6e8b72", - "reference": "b83773107a5b83a5507df9e88bd50d495f6e8b72", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/48a64e746857464a5e8fd7bab84b31c9ba967eb9", + "reference": "48a64e746857464a5e8fd7bab84b31c9ba967eb9", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.1", - "symfony/clock": "^6.3|^7.0", - "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.4.11|^7.1.4", + "php": ">=8.2", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^6.4.11|^7.1.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.2|^7.0", - "symfony/http-kernel": "^6.2", - "symfony/password-hasher": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.2|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/security-http": "^6.3.6|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/password-hasher": "^6.4|^7.0|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/security-http": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/browser-kit": "<5.4", - "symfony/console": "<5.4", + "symfony/browser-kit": "<6.4", + "symfony/console": "<6.4", "symfony/framework-bundle": "<6.4", - "symfony/http-client": "<5.4", - "symfony/ldap": "<5.4", + "symfony/http-client": "<6.4", + "symfony/ldap": "<6.4", "symfony/serializer": "<6.4", - "symfony/twig-bundle": "<5.4", + "symfony/twig-bundle": "<6.4", "symfony/validator": "<6.4" }, "require-dev": { - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dom-crawler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/ldap": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/twig-bridge": "^5.4|^6.0|^7.0", - "symfony/twig-bundle": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0", - "twig/twig": "^2.13|^3.0.4", - "web-token/jwt-checker": "^3.1", - "web-token/jwt-signature-algorithm-ecdsa": "^3.1", - "web-token/jwt-signature-algorithm-eddsa": "^3.1", - "web-token/jwt-signature-algorithm-hmac": "^3.1", - "web-token/jwt-signature-algorithm-none": "^3.1", - "web-token/jwt-signature-algorithm-rsa": "^3.1" + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/ldap": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0", + "twig/twig": "^3.15", + "web-token/jwt-library": "^3.3.2|^4.0" }, "type": "symfony-bundle", "autoload": { @@ -8480,7 +8307,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.4.26" + "source": "https://github.com/symfony/security-bundle/tree/v7.4.0" }, "funding": [ { @@ -8500,49 +8327,50 @@ "type": "tidelift" } ], - "time": "2025-09-22T15:03:07+00:00" + "time": "2025-11-14T09:57:20+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "673018434b38e504eb04ca3c6d7e2e7c86735bfb" + "reference": "fe4d25e5700a2f3b605bf23f520be57504ae5c51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/673018434b38e504eb04ca3c6d7e2e7c86735bfb", - "reference": "673018434b38e504eb04ca3c6d7e2e7c86735bfb", + "url": "https://api.github.com/repos/symfony/security-core/zipball/fe4d25e5700a2f3b605bf23f520be57504ae5c51", + "reference": "fe4d25e5700a2f3b605bf23f520be57504ae5c51", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/password-hasher": "^5.4|^6.0|^7.0", + "symfony/password-hasher": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/event-dispatcher": "<5.4", - "symfony/http-foundation": "<5.4", - "symfony/ldap": "<5.4", - "symfony/security-guard": "<5.4", - "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", - "symfony/validator": "<5.4" + "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": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/ldap": "^5.4|^6.0|^7.0", - "symfony/string": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", - "symfony/validator": "^6.4|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/ldap": "^6.4|^7.0|^8.0", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4.3|^7.0.3|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8570,7 +8398,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.27" + "source": "https://github.com/symfony/security-core/tree/v7.4.0" }, "funding": [ { @@ -8590,31 +8418,33 @@ "type": "tidelift" } ], - "time": "2025-10-23T19:49:35+00:00" + "time": "2025-11-21T15:26:00+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7" + "reference": "ec41009e83589d0b3d86bd131d07e6fc8ecf35ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/9a1efc8c10b86bcedc9233affd10c716b54ca1b7", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/ec41009e83589d0b3d86bd131d07e6fc8ecf35ab", + "reference": "ec41009e83589d0b3d86bd131d07e6fc8ecf35ab", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/security-core": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/security-core": "^6.4|^7.0|^8.0" }, "conflict": { - "symfony/http-foundation": "<5.4" + "symfony/http-foundation": "<6.4" }, "require-dev": { - "symfony/http-foundation": "^5.4|^6.0|^7.0" + "psr/log": "^1|^2|^3", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8642,7 +8472,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.24" + "source": "https://github.com/symfony/security-csrf/tree/v7.4.0" }, "funding": [ { @@ -8662,51 +8492,51 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-21T15:26:00+00:00" }, { "name": "symfony/security-http", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "6c2e236f0fc3e0853770a5574ef7af471486ba4c" + "reference": "92f9cc6494f3d29042ac35c2ee5209191bbbb781" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/6c2e236f0fc3e0853770a5574ef7af471486ba4c", - "reference": "6c2e236f0fc3e0853770a5574ef7af471486ba4c", + "url": "https://api.github.com/repos/symfony/security-http/zipball/92f9cc6494f3d29042ac35c2ee5209191bbbb781", + "reference": "92f9cc6494f3d29042ac35c2ee5209191bbbb781", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-foundation": "^6.2|^7.0", - "symfony/http-kernel": "^6.3|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/security-core": "^7.3|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/clock": "<6.3", - "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", + "symfony/clock": "<6.4", "symfony/http-client-contracts": "<3.0", - "symfony/security-bundle": "<5.4", - "symfony/security-csrf": "<5.4" + "symfony/security-bundle": "<6.4", + "symfony/security-csrf": "<6.4" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/clock": "^6.3|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^3.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "web-token/jwt-checker": "^3.1", - "web-token/jwt-signature-algorithm-ecdsa": "^3.1" + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "web-token/jwt-library": "^3.3.2|^4.0" }, "type": "library", "autoload": { @@ -8734,7 +8564,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.4.26" + "source": "https://github.com/symfony/security-http/tree/v7.4.0" }, "funding": [ { @@ -8754,61 +8584,62 @@ "type": "tidelift" } ], - "time": "2025-09-05T18:17:25+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/serializer", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "28779bbdb398cac3421d0e51f7ca669e4a27c5ac" + "reference": "5a3bbf317b3f1025126b6d9debce53515601ab43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/28779bbdb398cac3421d0e51f7ca669e4a27c5ac", - "reference": "28779bbdb398cac3421d0e51f7ca669e4a27c5ac", + "url": "https://api.github.com/repos/symfony/serializer/zipball/5a3bbf317b3f1025126b6d9debce53515601ab43", + "reference": "5a3bbf317b3f1025126b6d9debce53515601ab43", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php84": "^1.30" }, "conflict": { - "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<5.4", - "symfony/property-access": "<5.4", - "symfony/property-info": "<5.4.24|>=6,<6.2.11", - "symfony/uid": "<5.4", + "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": "<5.4" + "symfony/yaml": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4.26|^6.3|^7.0", - "symfony/property-info": "^5.4.24|^6.2.11|^7.0", + "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": "^7.2|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/type-info": "^7.1.8|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8836,7 +8667,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.4.27" + "source": "https://github.com/symfony/serializer/tree/v7.4.0" }, "funding": [ { @@ -8856,7 +8687,7 @@ "type": "tidelift" } ], - "time": "2025-10-08T04:24:22+00:00" + "time": "2025-11-18T13:23:20+00:00" }, { "name": "symfony/service-contracts", @@ -8947,20 +8778,20 @@ }, { "name": "symfony/stopwatch", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898" + "reference": "8a24af0a2e8a872fb745047180649b8418303084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b67e94e06a05d9572c2fa354483b3e13e3cb1898", - "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8a24af0a2e8a872fb745047180649b8418303084", + "reference": "8a24af0a2e8a872fb745047180649b8418303084", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -8989,7 +8820,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.4.24" + "source": "https://github.com/symfony/stopwatch/tree/v7.4.0" }, "funding": [ { @@ -9009,26 +8840,27 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "symfony/string", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea" + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/5621f039a71a11c87c106c1c598bdcd04a19aeea", - "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea", + "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003", + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -9036,10 +8868,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9078,7 +8911,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.26" + "source": "https://github.com/symfony/string/tree/v7.4.0" }, "funding": [ { @@ -9098,55 +8931,56 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:32:46+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/translation", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "c8559fe25c7ee7aa9d28f228903a46db008156a4" + "reference": "2d01ca0da3f092f91eeedb46f24aa30d2fca8f68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/c8559fe25c7ee7aa9d28f228903a46db008156a4", - "reference": "c8559fe25c7ee7aa9d28f228903a46db008156a4", + "url": "https://api.github.com/repos/symfony/translation/zipball/2d01ca0da3f092f91eeedb46f24aa30d2fca8f68", + "reference": "2d01ca0da3f092f91eeedb46f24aa30d2fca8f68", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { - "symfony/config": "<5.4", - "symfony/console": "<5.4", - "symfony/dependency-injection": "<5.4", + "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": "<5.4", + "symfony/http-kernel": "<6.4", "symfony/service-contracts": "<2.5", - "symfony/twig-bundle": "<5.4", - "symfony/yaml": "<5.4" + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" }, "provide": { "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "nikic/php-parser": "^4.18|^5.0", + "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.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/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9177,7 +9011,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.26" + "source": "https://github.com/symfony/translation/tree/v7.4.0" }, "funding": [ { @@ -9197,7 +9031,7 @@ "type": "tidelift" } ], - "time": "2025-09-05T18:17:25+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/translation-contracts", @@ -9283,68 +9117,70 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.4.25", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf" + "reference": "e96998da928007554b8b8c02e677861877daced9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/9d13e87591c9de3221c8d6f23cd9a2b5958607bf", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e96998da928007554b8b8c02e677861877daced9", + "reference": "e96998da928007554b8b8c02e677861877daced9", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^2.13|^3.0.4" + "twig/twig": "^3.21" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/console": "<5.4", - "symfony/form": "<6.3", - "symfony/http-foundation": "<5.4", + "symfony/console": "<6.4", + "symfony/form": "<6.4", + "symfony/http-foundation": "<6.4", "symfony/http-kernel": "<6.4", - "symfony/mime": "<6.2", + "symfony/mime": "<6.4", "symfony/serializer": "<6.4", - "symfony/translation": "<5.4", - "symfony/workflow": "<5.4" + "symfony/translation": "<6.4", + "symfony/workflow": "<6.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": "^5.4|^6.0|^7.0", - "symfony/asset-mapper": "^6.3|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^6.4.20|^7.2.5", - "symfony/html-sanitizer": "^6.1|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", - "symfony/mime": "^6.2|^7.0", + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/asset-mapper": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4.20|^7.2.5|^8.0", + "symfony/html-sanitizer": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^7.3|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^5.4|^6.0|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/security-http": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^6.1|^7.0", - "symfony/web-link": "^5.4|^6.0|^7.0", - "symfony/workflow": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0", - "twig/cssinliner-extra": "^2.12|^3", - "twig/inky-extra": "^2.12|^3", - "twig/markdown-extra": "^2.12|^3" + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/security-http": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/web-link": "^6.4|^7.0|^8.0", + "symfony/workflow": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0", + "twig/cssinliner-extra": "^3", + "twig/inky-extra": "^3", + "twig/markdown-extra": "^3" }, "type": "symfony-bridge", "autoload": { @@ -9372,7 +9208,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.25" + "source": "https://github.com/symfony/twig-bridge/tree/v7.4.0" }, "funding": [ { @@ -9392,47 +9228,48 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2025-11-05T14:29:59+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba" + "reference": "f83f530d00d1bbc6f7fafeb433077887c83326ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/3b48b6e8225495c6d2438828982b4d219ca565ba", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/f83f530d00d1bbc6f7fafeb433077887c83326ef", + "reference": "f83f530d00d1bbc6f7fafeb433077887c83326ef", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", - "php": ">=8.1", - "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.1|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^6.2", - "symfony/twig-bridge": "^6.4", - "twig/twig": "^2.13|^3.0.4" + "php": ">=8.2", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/twig-bridge": "^7.3|^8.0", + "twig/twig": "^3.12" }, "conflict": { - "symfony/framework-bundle": "<5.4", - "symfony/translation": "<5.4" + "symfony/framework-bundle": "<6.4", + "symfony/translation": "<6.4" }, "require-dev": { - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^5.4|^6.0|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/web-link": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/web-link": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -9460,7 +9297,90 @@ "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/v6.4.24" + "source": "https://github.com/symfony/twig-bundle/tree/v7.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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-10-02T07:41:02+00:00" + }, + { + "name": "symfony/type-info", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/type-info.git", + "reference": "7f9743e921abcce92a03fc693530209c59e73076" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/type-info/zipball/7f9743e921abcce92a03fc693530209c59e73076", + "reference": "7f9743e921abcce92a03fc693530209c59e73076", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "phpstan/phpdoc-parser": "<1.30" + }, + "require-dev": { + "phpstan/phpdoc-parser": "^1.30|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\TypeInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathias Arlaud", + "email": "mathias.arlaud@gmail.com" + }, + { + "name": "Baptiste LEDUC", + "email": "baptiste.leduc@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts PHP types information.", + "homepage": "https://symfony.com", + "keywords": [ + "PHPStan", + "phpdoc", + "symfony", + "type" + ], + "support": { + "source": "https://github.com/symfony/type-info/tree/v7.4.0" }, "funding": [ { @@ -9480,24 +9400,24 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-07T09:36:46+00:00" }, { "name": "symfony/validator", - "version": "v6.4.29", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "99df8a769e64e399f510166141ea74f450e8dd1d" + "reference": "829d4acbecc6a9c097ca9cb118d7f96f46d33da9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/99df8a769e64e399f510166141ea74f450e8dd1d", - "reference": "99df8a769e64e399f510166141ea74f450e8dd1d", + "url": "https://api.github.com/repos/symfony/validator/zipball/829d4acbecc6a9c097ca9cb118d7f96f46d33da9", + "reference": "829d4acbecc6a9c097ca9cb118d7f96f46d33da9", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", @@ -9505,34 +9425,37 @@ "symfony/translation-contracts": "^2.5|^3" }, "conflict": { - "doctrine/annotations": "<1.13", "doctrine/lexer": "<1.1", - "symfony/dependency-injection": "<5.4", - "symfony/expression-language": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/intl": "<5.4", - "symfony/property-info": "<5.4", - "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", - "symfony/yaml": "<5.4" + "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/var-exporter": "<6.4.25|>=7.0,<7.3.3", + "symfony/yaml": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.13|^2", "egulias/email-validator": "^2.1.10|^3|^4", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", - "symfony/yaml": "^5.4|^6.0|^7.0" + "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/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/process": "^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/string": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4.3|^7.0.3|^8.0", + "symfony/type-info": "^7.1.8", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9561,7 +9484,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.29" + "source": "https://github.com/symfony/validator/tree/v7.4.0" }, "funding": [ { @@ -9581,37 +9504,36 @@ "type": "tidelift" } ], - "time": "2025-11-06T20:26:06+00:00" + "time": "2025-11-18T13:23:20+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a" + "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cfae1497a2f1eaad78dbc0590311c599c7178d4a", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece", + "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/console": "<5.4" + "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^6.3|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/uid": "^5.4|^6.0|^7.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" }, "bin": [ "Resources/bin/var-dump-server" @@ -9649,7 +9571,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.26" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.0" }, "funding": [ { @@ -9669,30 +9591,30 @@ "type": "tidelift" } ], - "time": "2025-09-25T15:37:27+00:00" + "time": "2025-10-27T20:36:44+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc" + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/466fcac5fa2e871f83d31173f80e9c2684743bfc", - "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9730,7 +9652,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.26" + "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" }, "funding": [ { @@ -9750,42 +9672,46 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-09-11T10:15:23+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "4c2ab411372e8bd854678cd7c81f1a9bfd6914aa" + "reference": "dcd955ca9c60f2942194854518049f8ae4dbd696" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4c2ab411372e8bd854678cd7c81f1a9bfd6914aa", - "reference": "4c2ab411372e8bd854678cd7c81f1a9bfd6914aa", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/dcd955ca9c60f2942194854518049f8ae4dbd696", + "reference": "dcd955ca9c60f2942194854518049f8ae4dbd696", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/twig-bundle": "^5.4|^6.0", - "twig/twig": "^2.13|^3.0.4" + "composer-runtime-api": ">=2.1", + "php": ">=8.2", + "symfony/config": "^7.3|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "twig/twig": "^3.15" }, "conflict": { - "symfony/form": "<5.4", - "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/twig-bundle": ">=7.0" + "symfony/form": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/serializer": "<7.2", + "symfony/workflow": "<7.3" }, "require-dev": { - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -9816,7 +9742,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.27" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.4.0" }, "funding": [ { @@ -9836,32 +9762,32 @@ "type": "tidelift" } ], - "time": "2025-10-05T13:55:43+00:00" + "time": "2025-11-19T14:48:01+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0fc8b966fd0dcaab544ae59bfc3a433f048c17b0" + "reference": "6c84a4b55aee4cd02034d1c528e83f69ddf63810" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0fc8b966fd0dcaab544ae59bfc3a433f048c17b0", - "reference": "0fc8b966fd0dcaab544ae59bfc3a433f048c17b0", + "url": "https://api.github.com/repos/symfony/yaml/zipball/6c84a4b55aee4cd02034d1c528e83f69ddf63810", + "reference": "6c84a4b55aee4cd02034d1c528e83f69ddf63810", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.4" + "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -9892,7 +9818,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.26" + "source": "https://github.com/symfony/yaml/tree/v7.4.0" }, "funding": [ { @@ -9912,7 +9838,7 @@ "type": "tidelift" } ], - "time": "2025-09-26T15:07:38+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "twig/extra-bundle", @@ -12410,33 +12336,30 @@ }, { "name": "symfony/debug-bundle", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "21a61c55192d558a6b81cdb12e8c010fc9474fe0" + "reference": "329383fb895353e3c8ab792cc35c4a7e7b17881b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/21a61c55192d558a6b81cdb12e8c010fc9474fe0", - "reference": "21a61c55192d558a6b81cdb12e8c010fc9474fe0", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/329383fb895353e3c8ab792cc35c4a7e7b17881b", + "reference": "329383fb895353e3c8ab792cc35c4a7e7b17881b", "shasum": "" }, "require": { + "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.1", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/twig-bridge": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" - }, - "conflict": { - "symfony/config": "<5.4", - "symfony/dependency-injection": "<5.4" + "php": ">=8.2", + "symfony/config": "^7.3|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "require-dev": { - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0" + "symfony/web-profiler-bundle": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -12464,7 +12387,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/v6.4.27" + "source": "https://github.com/symfony/debug-bundle/tree/v7.4.0" }, "funding": [ { @@ -12484,7 +12407,7 @@ "type": "tidelift" } ], - "time": "2025-10-11T17:35:31+00:00" + "time": "2025-10-24T13:56:35+00:00" }, { "name": "symfony/maker-bundle", @@ -12586,28 +12509,24 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "406aa80401bf960e7a173a3ccf268ae82b6bc93f" + "reference": "059b051b38f2138ef104dd848fa48f0cbbb7d78b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/406aa80401bf960e7a173a3ccf268ae82b6bc93f", - "reference": "406aa80401bf960e7a173a3ccf268ae82b6bc93f", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/059b051b38f2138ef104dd848fa48f0cbbb7d78b", + "reference": "059b051b38f2138ef104dd848fa48f0cbbb7d78b", "shasum": "" }, "require": { - "php": ">=7.1.3" - }, - "conflict": { - "phpunit/phpunit": "<7.5|9.1.2" + "php": ">=8.1.0" }, "require-dev": { - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/polyfill-php81": "^1.27" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4.3|^7.0.3|^8.0" }, "bin": [ "bin/simple-phpunit" @@ -12651,7 +12570,7 @@ "testing" ], "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.26" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.4.0" }, "funding": [ { @@ -12671,24 +12590,24 @@ "type": "tidelift" } ], - "time": "2025-09-12T08:37:02+00:00" + "time": "2025-10-28T22:44:23+00:00" }, { "name": "symfony/process", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8" + "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8", - "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8", + "url": "https://api.github.com/repos/symfony/process/zipball/7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", + "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -12716,7 +12635,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.26" + "source": "https://github.com/symfony/process/tree/v7.4.0" }, "funding": [ { @@ -12736,7 +12655,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-10-16T11:21:06+00:00" }, { "name": "theseer/tokenizer", @@ -12795,7 +12714,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.1.0", + "php": "^8.2.0", "ext-bcmath": "*", "ext-ctype": "*", "ext-curl": "*", @@ -12815,7 +12734,7 @@ "ext-dom": "*" }, "platform-overrides": { - "php": "8.1.0" + "php": "8.2.0" }, "plugin-api-version": "2.9.0" } diff --git a/webapp/config/packages/doctrine.yaml b/webapp/config/packages/doctrine.yaml index 89bf0223b3..4b9294a015 100644 --- a/webapp/config/packages/doctrine.yaml +++ b/webapp/config/packages/doctrine.yaml @@ -17,7 +17,7 @@ doctrine: internal_error_status: App\Doctrine\DBAL\Types\InternalErrorStatusType judge_task_type: App\Doctrine\DBAL\Types\JudgeTaskType mapping_types: - enum: string + enum: enum schema_filter: ~^(?!sessions)~ # IMPORTANT: You MUST configure your server version, # either here or in the DATABASE_URL env var (see .env file) diff --git a/webapp/config/packages/framework.yaml b/webapp/config/packages/framework.yaml index 21a3cec7bc..cd363ae966 100644 --- a/webapp/config/packages/framework.yaml +++ b/webapp/config/packages/framework.yaml @@ -24,6 +24,9 @@ framework: assets: version: "v=%domjudge.version%" + property_info: + with_constructor_extractor: true + when@test: framework: test: true diff --git a/webapp/config/packages/twig.yaml b/webapp/config/packages/twig.yaml index 73e49bc00c..350e58b8ff 100644 --- a/webapp/config/packages/twig.yaml +++ b/webapp/config/packages/twig.yaml @@ -3,7 +3,6 @@ twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' form_themes: ['form_theme.html.twig'] - exception_controller: null globals: DOMJUDGE_VERSION: '%domjudge.version%' DJ_CHARACTER_SET: 'utf-8' diff --git a/webapp/config/packages/twig_extensions.yaml b/webapp/config/packages/twig_extensions.yaml index a4f392d925..88c952e6cd 100644 --- a/webapp/config/packages/twig_extensions.yaml +++ b/webapp/config/packages/twig_extensions.yaml @@ -8,4 +8,3 @@ services: #Twig\Extensions\ArrayExtension: ~ #Twig\Extensions\DateExtension: ~ #Twig\Extensions\IntlExtension: ~ - Twig\Extensions\TextExtension: ~ diff --git a/webapp/config/packages/web_profiler.yaml b/webapp/config/packages/web_profiler.yaml index b94611102d..997f52159c 100644 --- a/webapp/config/packages/web_profiler.yaml +++ b/webapp/config/packages/web_profiler.yaml @@ -14,4 +14,6 @@ when@test: intercept_redirects: false framework: - profiler: { collect: false } + profiler: + collect: false + collect_serializer_data: true diff --git a/webapp/config/reference.php b/webapp/config/reference.php new file mode 100644 index 0000000000..20df0cf2ba --- /dev/null +++ b/webapp/config/reference.php @@ -0,0 +1,2189 @@ + [ + * 'App\\' => [ + * 'resource' => '../src/', + * ], + * ], + * ]); + * ``` + * + * @psalm-type ImportsConfig = list + * @psalm-type ParametersConfig = array|null>|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 + * @psalm-type CallbackType = string|array{0:string|ReferenceConfigurator,1:string}|\Closure|ReferenceConfigurator|ExpressionConfigurator + * @psalm-type DeprecationType = array{package: string, version: string, message?: string} + * @psalm-type DefaultsType = array{ + * public?: bool, + * tags?: TagsType, + * resource_tags?: TagsType, + * autowire?: bool, + * autoconfigure?: bool, + * bind?: array, + * } + * @psalm-type InstanceofType = array{ + * shared?: bool, + * lazy?: bool|string, + * public?: bool, + * properties?: array, + * configurator?: CallbackType, + * calls?: list, + * tags?: TagsType, + * resource_tags?: TagsType, + * autowire?: bool, + * bind?: array, + * constructor?: string, + * } + * @psalm-type DefinitionType = array{ + * class?: string, + * file?: string, + * parent?: string, + * shared?: bool, + * synthetic?: bool, + * lazy?: bool|string, + * public?: bool, + * abstract?: bool, + * deprecated?: DeprecationType, + * factory?: CallbackType, + * configurator?: CallbackType, + * arguments?: ArgumentsType, + * properties?: array, + * calls?: list, + * tags?: TagsType, + * resource_tags?: TagsType, + * decorates?: string, + * decoration_inner_name?: string, + * decoration_priority?: int, + * decoration_on_invalid?: 'exception'|'ignore'|null, + * autowire?: bool, + * autoconfigure?: bool, + * bind?: array, + * constructor?: string, + * from_callable?: CallbackType, + * } + * @psalm-type AliasType = string|array{ + * alias: string, + * public?: bool, + * deprecated?: DeprecationType, + * } + * @psalm-type PrototypeType = array{ + * resource: string, + * namespace?: string, + * exclude?: string|list, + * parent?: string, + * shared?: bool, + * lazy?: bool|string, + * public?: bool, + * abstract?: bool, + * deprecated?: DeprecationType, + * factory?: CallbackType, + * arguments?: ArgumentsType, + * properties?: array, + * configurator?: CallbackType, + * calls?: list, + * tags?: TagsType, + * resource_tags?: TagsType, + * autowire?: bool, + * autoconfigure?: bool, + * bind?: array, + * constructor?: string, + * } + * @psalm-type StackType = array{ + * stack: list>, + * public?: bool, + * deprecated?: DeprecationType, + * } + * @psalm-type ServicesConfig = array{ + * _defaults?: DefaultsType, + * _instanceof?: InstanceofType, + * ... + * } + * @psalm-type ExtensionType = array + * @psalm-type DoctrineConfig = array{ + * dbal?: array{ + * default_connection?: scalar|null, + * types?: 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, + * 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" + * 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 + * }, + * 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 + * second_level_cache?: array{ + * region_cache_driver?: string|array{ + * type?: scalar|null, // Default: null + * id?: scalar|null, + * pool?: scalar|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, + * regions?: array, + * loggers?: array, + * }, + * hydrators?: array, + * mappings?: array, + * dql?: array{ + * string_functions?: array, + * numeric_functions?: array, + * datetime_functions?: array, + * }, + * filters?: array, + * }>, + * identity_generation_preferences?: array, + * }>, + * resolve_target_entities?: array, + * }, + * } + * @psalm-type JmsSerializerConfig = array{ + * twig_enabled?: scalar|null, // Default: "default" + * profiler?: scalar|null, // Default: true + * enum_support?: scalar|null, // Default: false + * default_value_property_reader_support?: scalar|null, // Default: false + * handlers?: array{ + * datetime?: array{ + * default_format?: scalar|null, // Default: "Y-m-d\\TH:i:sP" + * default_deserialization_formats?: list, + * default_timezone?: scalar|null, // Default: "Europe/Berlin" + * cdata?: scalar|null, // Default: true + * }, + * array_collection?: array{ + * initialize_excluded?: bool, // Default: false + * }, + * symfony_uid?: array{ + * default_format?: scalar|null, // Default: "canonical" + * cdata?: scalar|null, // Default: true + * }, + * }, + * subscribers?: array{ + * doctrine_proxy?: array{ + * initialize_excluded?: bool, // Default: false + * initialize_virtual_types?: bool, // Default: false + * }, + * }, + * object_constructors?: array{ + * doctrine?: bool|array{ + * enabled?: bool, // Default: true + * fallback_strategy?: "null"|"exception"|"fallback", // Default: "null" + * }, + * }, + * property_naming?: string|array{ + * id?: scalar|null, + * separator?: scalar|null, // Default: "_" + * lower_case?: bool, // Default: true + * }, + * expression_evaluator?: string|array{ + * id?: scalar|null, // Default: "jms_serializer.expression_evaluator" + * }, + * metadata?: array{ + * warmup?: array{ + * paths?: array{ + * included?: list, + * excluded?: list, + * }, + * }, + * cache?: scalar|null, // Default: "file" + * debug?: bool, // Default: true + * file_cache?: array{ + * dir?: scalar|null, // Default: null + * }, + * include_interfaces?: bool, // Default: false + * auto_detection?: bool, // Default: true + * infer_types_from_doc_block?: bool, // Default: false + * infer_types_from_doctrine_metadata?: bool, // Infers type information from Doctrine metadata if no explicit type has been defined for a property. // Default: true + * directories?: array, + * }, + * visitors?: array{ + * json_serialization?: array{ + * depth?: scalar|null, + * options?: scalar|null, // Default: 1024 + * }, + * json_deserialization?: array{ + * options?: scalar|null, // Default: 0 + * strict?: bool, // Default: false + * }, + * xml_serialization?: array{ + * version?: scalar|null, + * encoding?: scalar|null, + * format_output?: bool, // Default: false + * default_root_name?: scalar|null, + * default_root_ns?: scalar|null, // Default: "" + * }, + * xml_deserialization?: array{ + * doctype_whitelist?: list, + * external_entities?: bool, // Default: false + * options?: scalar|null, // Default: 0 + * }, + * }, + * default_context?: array{ + * serialization?: string|array{ + * id?: scalar|null, + * serialize_null?: scalar|null, // Flag if null values should be serialized + * enable_max_depth_checks?: scalar|null, // Flag to enable the max-depth exclusion strategy + * attributes?: array, + * groups?: list, + * version?: scalar|null, // Application version to use in exclusion strategies + * }, + * deserialization?: string|array{ + * id?: scalar|null, + * serialize_null?: scalar|null, // Flag if null values should be serialized + * enable_max_depth_checks?: scalar|null, // Flag to enable the max-depth exclusion strategy + * attributes?: array, + * groups?: list, + * version?: scalar|null, // Application version to use in exclusion strategies + * }, + * }, + * instances?: array, + * default_timezone?: scalar|null, // Default: "Europe/Berlin" + * cdata?: scalar|null, // Default: true + * }, + * array_collection?: array{ + * initialize_excluded?: bool, // Default: false + * }, + * symfony_uid?: array{ + * default_format?: scalar|null, // Default: "canonical" + * cdata?: scalar|null, // Default: true + * }, + * }, + * subscribers?: array{ + * doctrine_proxy?: array{ + * initialize_excluded?: bool, // Default: false + * initialize_virtual_types?: bool, // Default: false + * }, + * }, + * object_constructors?: array{ + * doctrine?: bool|array{ + * enabled?: bool, // Default: true + * fallback_strategy?: "null"|"exception"|"fallback", // Default: "null" + * }, + * }, + * property_naming?: string|array{ + * id?: scalar|null, + * separator?: scalar|null, // Default: "_" + * lower_case?: bool, // Default: true + * }, + * expression_evaluator?: string|array{ + * id?: scalar|null, // Default: "jms_serializer.expression_evaluator" + * }, + * metadata?: array{ + * warmup?: array{ + * paths?: array{ + * included?: list, + * excluded?: list, + * }, + * }, + * cache?: scalar|null, // Default: "file" + * debug?: bool, // Default: true + * file_cache?: array{ + * dir?: scalar|null, // Default: null + * }, + * include_interfaces?: bool, // Default: false + * auto_detection?: bool, // Default: true + * infer_types_from_doc_block?: bool, // Default: false + * infer_types_from_doctrine_metadata?: bool, // Infers type information from Doctrine metadata if no explicit type has been defined for a property. // Default: true + * directories?: array, + * }, + * visitors?: array{ + * json_serialization?: array{ + * depth?: scalar|null, + * options?: scalar|null, // Default: 1024 + * }, + * json_deserialization?: array{ + * options?: scalar|null, // Default: 0 + * strict?: bool, // Default: false + * }, + * xml_serialization?: array{ + * version?: scalar|null, + * encoding?: scalar|null, + * format_output?: bool, // Default: false + * default_root_name?: scalar|null, + * default_root_ns?: scalar|null, // Default: "" + * }, + * xml_deserialization?: array{ + * doctype_whitelist?: list, + * external_entities?: bool, // Default: false + * options?: scalar|null, // Default: 0 + * }, + * }, + * default_context?: array{ + * serialization?: string|array{ + * id?: scalar|null, + * serialize_null?: scalar|null, // Flag if null values should be serialized + * enable_max_depth_checks?: scalar|null, // Flag to enable the max-depth exclusion strategy + * attributes?: array, + * groups?: list, + * version?: scalar|null, // Application version to use in exclusion strategies + * }, + * deserialization?: string|array{ + * id?: scalar|null, + * serialize_null?: scalar|null, // Flag if null values should be serialized + * enable_max_depth_checks?: scalar|null, // Flag to enable the max-depth exclusion strategy + * attributes?: array, + * groups?: list, + * version?: scalar|null, // Application version to use in exclusion strategies + * }, + * }, + * }>, + * } + * @psalm-type NelmioApiDocConfig = array{ + * type_info?: bool, // Use the symfony/type-info component for determining types. // Default: false + * use_validation_groups?: bool, // If true, `groups` passed to #[Model] attributes will be used to limit validation constraints // Default: false + * operation_id_generation?: \Nelmio\ApiDocBundle\Describer\OperationIdGeneration::ALWAYS_PREPEND|\Nelmio\ApiDocBundle\Describer\OperationIdGeneration::CONDITIONALLY_PREPEND|\Nelmio\ApiDocBundle\Describer\OperationIdGeneration::NO_PREPEND|"always_prepend"|"conditionally_prepend"|"no_prepend", // How to generate operation ids // Default: "always_prepend" + * cache?: array{ + * pool?: scalar|null, // define cache pool to use // Default: null + * item_id?: scalar|null, // define cache item id // Default: null + * }, + * documentation?: array, + * media_types?: list, + * html_config?: array{ // UI configuration options + * assets_mode?: scalar|null, // Default: "cdn" + * swagger_ui_config?: array, + * redocly_config?: array, + * stoplight_config?: array, + * }, + * areas?: array, + * host_patterns?: list, + * name_patterns?: list, + * security?: array + * }>, + * with_attribute?: bool, // whether to filter by attributes // Default: false + * disable_default_routes?: bool, // if set disables default routes without attributes // Default: false + * documentation?: array, + * cache?: array{ + * pool?: scalar|null, // define cache pool to use // Default: null + * item_id?: scalar|null, // define cache item id // Default: null + * }, + * }>, + * models?: array{ + * use_jms?: bool, // Default: false + * names?: list, + * areas?: list, + * }>, + * }, + * } + * @psalm-type MonologConfig = array{ + * use_microseconds?: scalar|null, // Default: true + * channels?: list, + * handlers?: array, + * excluded_http_codes?: 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" + * room?: scalar|null, + * message_format?: scalar|null, // Default: "text" + * api_version?: scalar|null, // Default: null + * 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, + * team?: scalar|null, + * notify?: scalar|null, // Default: false + * nickname?: scalar|null, // Default: "Monolog" + * token?: scalar|null, + * region?: scalar|null, + * source?: scalar|null, + * use_ssl?: bool, // 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, + * dsn?: scalar|null, + * hub_id?: scalar|null, // Default: null + * client_id?: scalar|null, // Default: null + * auto_log_stacks?: scalar|null, // Default: false + * release?: scalar|null, // Default: null + * environment?: scalar|null, // Default: null + * 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, + * console_formater_options?: mixed, // Deprecated: "monolog.handlers..console_formater_options.console_formater_options" is deprecated, use "monolog.handlers..console_formater_options.console_formatter_options" instead. + * console_formatter_options?: mixed, // Default: [] + * formatter?: scalar|null, + * nested?: bool, // 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", + * }, + * mongo?: string|array{ + * id?: scalar|null, + * host?: scalar|null, + * port?: scalar|null, // Default: 27017 + * user?: scalar|null, + * pass?: scalar|null, + * database?: scalar|null, // Default: "monolog" + * collection?: scalar|null, // Default: "logs" + * }, + * 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" + * }, + * 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 + * }, + * index?: scalar|null, // Default: "monolog" + * document_type?: scalar|null, // Default: "logs" + * ignore_error?: scalar|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" + * }, + * predis?: string|array{ + * id?: scalar|null, + * host?: scalar|null, + * }, + * from_email?: scalar|null, + * to_email?: list, + * subject?: scalar|null, + * content_type?: scalar|null, // Default: null + * headers?: list, + * mailer?: scalar|null, // Default: null + * email_prototype?: string|array{ + * id: scalar|null, + * method?: scalar|null, // Default: null + * }, + * lazy?: bool, // Default: true + * 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" + * }, + * channels?: string|array{ + * type?: scalar|null, + * elements?: list, + * }, + * }>, + * } + * @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, + * 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 + * 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" + * }, + * 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, + * }, + * }, + * 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, + * }, + * esi?: bool|array{ // ESI configuration + * enabled?: bool, // Default: false + * }, + * ssi?: bool|array{ // SSI configuration + * enabled?: bool, // Default: false + * }, + * fragments?: bool|array{ // Fragments configuration + * enabled?: bool, // Default: false + * hinclude_default_template?: scalar|null, // Default: null + * path?: scalar|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 + * }, + * workflows?: bool|array{ + * enabled?: bool, // Default: false + * workflows?: array, + * definition_validators?: list, + * support_strategy?: scalar|null, + * initial_marking?: list, + * events_to_dispatch?: list|null, + * places?: list, + * }>, + * transitions: list, + * to?: list, + * weight?: int, // 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 + * }, + * 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. + * }, + * request?: bool|array{ // Request configuration + * enabled?: bool, // 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, + * packages?: array, + * }>, + * }, + * asset_mapper?: bool|array{ // Asset Mapper configuration + * enabled?: bool, // Default: false + * 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" + * precompress?: bool|array{ // Precompress assets with Brotli, Zstandard and gzip. + * enabled?: bool, // 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, + * 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, + * }, + * providers?: array, + * locales?: list, + * }>, + * globals?: array, + * domain?: string, + * }>, + * }, + * 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" + * mapping?: array{ + * 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 + * }, + * disable_translation?: bool, // Default: false + * auto_mapping?: array, + * }>, + * }, + * 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, + * mapping?: array{ + * 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 + * }>, + * }, + * 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 + * }, + * type_info?: bool|array{ // Type info configuration + * enabled?: bool, // Default: true + * aliases?: array, + * }, + * property_info?: bool|array{ // Property info configuration + * enabled?: bool, // Default: true + * with_constructor_extractor?: bool, // Registers the constructor extractor. + * }, + * 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 + * 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, + * }>, + * }, + * 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 + * }, + * exceptions?: array, + * web_link?: bool|array{ // Web links configuration + * enabled?: bool, // Default: false + * }, + * lock?: bool|string|array{ // Lock configuration + * enabled?: bool, // Default: false + * resources?: array>, + * }, + * semaphore?: bool|string|array{ // Semaphore configuration + * enabled?: bool, // Default: false + * resources?: array, + * }, + * messenger?: bool|array{ // Messenger configuration + * enabled?: bool, // Default: false + * routing?: array, + * }>, + * serializer?: array{ + * default_serializer?: scalar|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" + * context?: array, + * }, + * }, + * transports?: array, + * failure_transport?: scalar|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 + * }, + * rate_limiter?: scalar|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 + * buses?: array, + * }>, + * }>, + * }, + * scheduler?: bool|array{ // Scheduler configuration + * enabled?: bool, // Default: false + * }, + * disallow_search_engine_index?: bool, // 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. + * default_options?: array{ + * headers?: array, + * vars?: list, + * 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"...) + * 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. + * extra?: list, + * rate_limiter?: scalar|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 + * }, + * retry_failed?: bool|array{ + * enabled?: bool, // Default: false + * retry_strategy?: scalar|null, // service id to override the retry strategy. // Default: null + * http_codes?: array, + * }>, + * 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 + * }, + * }, + * mock_response_factory?: scalar|null, // The id of the service that should generate mock responses. It should be either an invokable or an iterable. + * scoped_clients?: array, + * headers?: array, + * max_redirects?: int, // 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"...). + * 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. + * extra?: list, + * rate_limiter?: scalar|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 + * }, + * retry_failed?: bool|array{ + * enabled?: bool, // Default: false + * retry_strategy?: scalar|null, // service id to override the retry strategy. // Default: null + * http_codes?: array, + * }>, + * 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 + * }, + * }>, + * }, + * mailer?: bool|array{ // Mailer configuration + * enabled?: bool, // Default: false + * 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, + * envelope?: array{ // Mailer Envelope configuration + * sender?: scalar|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: "" + * 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 + * }, + * 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 + * }, + * }, + * 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" + * }, + * notifier?: bool|array{ // Notifier configuration + * enabled?: bool, // Default: false + * 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>, + * admin_recipients?: list, + * }, + * rate_limiter?: bool|array{ // Rate limiter configuration + * enabled?: bool, // 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). + * 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 + * }, + * }>, + * }, + * 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, + * }, + * html_sanitizer?: bool|array{ // HtmlSanitizer configuration + * enabled?: bool, // Default: true + * sanitizers?: array, + * 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 + * }>, + * }, + * webhook?: bool|array{ // Webhook configuration + * enabled?: bool, // Default: false + * message_bus?: scalar|null, // The message bus to use. // Default: "messenger.default_bus" + * routing?: array, + * }, + * remote-event?: bool|array{ // RemoteEvent configuration + * enabled?: bool, // Default: false + * }, + * json_streamer?: bool|array{ // JSON streamer configuration + * enabled?: bool, // Default: false + * }, + * } + * @psalm-type TwigConfig = array{ + * 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, + * 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 + * }, + * 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: "," + * }, + * mailer?: array{ + * html_to_text_converter?: scalar|null, // A service implementing the "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface". // Default: null + * }, + * } + * @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_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 + * }, + * 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, + * }>, + * providers?: array, + * }, + * 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 + * }, + * memory?: array{ + * users?: array, + * }>, + * }, + * 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 + * }, + * }>, + * 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, + * 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">, + * 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 + * }, + * 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 + * }, + * 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" + * }, + * remote_user?: array{ + * provider?: scalar|null, + * user?: scalar|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" + * }, + * 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" + * }, + * 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: "" + * }, + * 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" + * }, + * 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: "" + * }, + * 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, + * token_handler: string|array{ + * id?: scalar|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). + * discovery?: array{ // Enable the OIDC discovery. + * cache?: array{ + * id: scalar|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. + * }, + * oidc?: array{ + * discovery?: array{ // Enable the OIDC discovery. + * base_uri: list, + * cache?: array{ + * id: scalar|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). + * 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). + * }, + * }, + * 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 + * }, + * oauth2?: scalar|null, + * }, + * }, + * http_basic?: array{ + * provider?: scalar|null, + * realm?: scalar|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: "" + * }, + * remember_me?: array{ + * secret?: scalar|null, // Default: "%kernel.secret%" + * service?: scalar|null, + * user_providers?: list, + * catch_exceptions?: bool, // Default: true + * signature_properties?: list, + * token_provider?: string|array{ + * service?: scalar|null, // The service ID of a custom remember-me token provider. + * doctrine?: bool|array{ + * enabled?: bool, // Default: false + * connection?: scalar|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: null + * httponly?: bool, // Default: true + * samesite?: null|"lax"|"strict"|"none", // Default: "lax" + * always_remember_me?: bool, // Default: false + * remember_me_parameter?: scalar|null, // Default: "_remember_me" + * }, + * }>, + * access_control?: list, + * attributes?: array, + * route?: scalar|null, // Default: null + * methods?: list, + * allow_if?: scalar|null, // Default: null + * roles?: list, + * }>, + * role_hierarchy?: array>, + * } + * @psalm-type FosRestConfig = array{ + * disable_csrf_role?: scalar|null, // Default: null + * unauthorized_challenge?: scalar|null, // Default: null + * param_fetcher_listener?: bool|string|array{ + * enabled?: bool, // Default: false + * force?: bool, // Default: false + * service?: scalar|null, // Default: null + * }, + * cache_dir?: scalar|null, // Default: "%kernel.cache_dir%/fos_rest" + * allowed_methods_listener?: bool|array{ + * enabled?: bool, // Default: false + * service?: scalar|null, // Default: null + * }, + * routing_loader?: bool, // Default: false + * body_converter?: bool|array{ + * enabled?: bool, // Default: false + * validate?: scalar|null, // Default: false + * validation_errors_argument?: scalar|null, // Default: "validationErrors" + * }, + * service?: array{ + * serializer?: scalar|null, // Default: null + * view_handler?: scalar|null, // Default: "fos_rest.view_handler.default" + * validator?: scalar|null, // Default: "validator" + * }, + * serializer?: array{ + * version?: scalar|null, // Default: null + * groups?: list, + * serialize_null?: bool, // Default: false + * }, + * zone?: list, + * ips?: list, + * }>, + * view?: array{ + * mime_types?: bool|array{ + * enabled?: bool, // Default: false + * service?: scalar|null, // Default: null + * formats?: array>, + * }, + * formats?: array, + * view_response_listener?: bool|string|array{ + * enabled?: bool, // Default: false + * force?: bool, // Default: false + * service?: scalar|null, // Default: null + * }, + * failed_validation?: scalar|null, // Default: 400 + * empty_content?: scalar|null, // Default: 204 + * serialize_null?: bool, // Default: false + * jsonp_handler?: array{ + * callback_param?: scalar|null, // Default: "callback" + * mime_type?: scalar|null, // Default: "application/javascript+jsonp" + * }, + * }, + * exception?: bool|array{ + * enabled?: bool, // Default: false + * map_exception_codes?: bool, // Enables an event listener that maps exception codes to response status codes based on the map configured with the "fos_rest.exception.codes" option. // Default: false + * exception_listener?: bool, // Default: false + * serialize_exceptions?: bool, // Default: false + * flatten_exception_format?: "legacy"|"rfc7807", // Default: "legacy" + * serializer_error_renderer?: bool, // Default: false + * codes?: array, + * messages?: array, + * debug?: bool, // Default: true + * }, + * body_listener?: bool|array{ + * enabled?: bool, // Default: false + * service?: scalar|null, // Default: null + * default_format?: scalar|null, // Default: null + * throw_exception_on_unsupported_content_type?: bool, // Default: false + * decoders?: array, + * array_normalizer?: string|array{ + * service?: scalar|null, // Default: null + * forms?: bool, // Default: false + * }, + * }, + * format_listener?: bool|array{ + * enabled?: bool, // Default: false + * service?: scalar|null, // Default: null + * rules?: list, + * stop?: bool, // Default: false + * prefer_extension?: bool, // Default: true + * fallback_format?: scalar|null, // Default: "html" + * priorities?: list, + * }>, + * }, + * versioning?: bool|array{ + * enabled?: bool, // Default: false + * default_version?: scalar|null, // Default: null + * resolvers?: array{ + * query?: bool|array{ + * enabled?: bool, // Default: true + * parameter_name?: scalar|null, // Default: "version" + * }, + * custom_header?: bool|array{ + * enabled?: bool, // Default: true + * header_name?: scalar|null, // Default: "X-Accept-Version" + * }, + * media_type?: bool|array{ + * enabled?: bool, // Default: true + * regex?: scalar|null, // Default: "/(v|version)=(?P[0-9\\.]+)/" + * }, + * }, + * guessing_order?: list, + * }, + * } + * @psalm-type WebProfilerConfig = array{ + * toolbar?: bool|array{ // Profiler toolbar configuration + * enabled?: bool, // Default: false + * ajax_replace?: bool, // 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 DoctrineMigrationsConfig = array{ + * enable_service_migrations?: bool, // 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 + * }, + * }, + * 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 + * } + * @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" + * } + * @psalm-type MakerConfig = array{ + * root_namespace?: scalar|null, // Default: "App" + * generate_final_classes?: bool, // Default: true + * generate_final_entities?: bool, // Default: false + * } + * @psalm-type TwigExtraConfig = array{ + * cache?: bool|array{ + * enabled?: bool, // Default: false + * }, + * html?: bool|array{ + * enabled?: bool, // Default: false + * }, + * markdown?: bool|array{ + * enabled?: bool, // Default: true + * }, + * intl?: bool|array{ + * enabled?: bool, // Default: false + * }, + * cssinliner?: bool|array{ + * enabled?: bool, // Default: false + * }, + * inky?: bool|array{ + * enabled?: bool, // Default: false + * }, + * string?: bool|array{ + * enabled?: bool, // Default: true + * }, + * commonmark?: array{ + * renderer?: array{ // Array of options for rendering HTML. + * block_separator?: scalar|null, + * inner_separator?: scalar|null, + * soft_break?: scalar|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 + * slug_normalizer?: array{ // Array of options for configuring how URL-safe slugs are created. + * instance?: mixed, + * max_length?: int, // 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, + * }, + * ... + * }, + * } + * @psalm-type NelmioCorsConfig = array{ + * defaults?: array{ + * allow_credentials?: bool, // Default: false + * allow_origin?: list, + * allow_headers?: list, + * allow_methods?: list, + * allow_private_network?: bool, // Default: false + * expose_headers?: list, + * max_age?: scalar|null, // Default: 0 + * hosts?: list, + * origin_regex?: bool, // Default: false + * forced_allow_origin_value?: scalar|null, // Default: null + * skip_same_as_origin?: bool, // Default: true + * }, + * paths?: array, + * allow_headers?: list, + * allow_methods?: list, + * allow_private_network?: bool, + * expose_headers?: list, + * max_age?: scalar|null, // Default: 0 + * hosts?: list, + * origin_regex?: bool, + * forced_allow_origin_value?: scalar|null, // Default: null + * skip_same_as_origin?: bool, + * }>, + * } + * @psalm-type KnpPaginatorConfig = array{ + * default_options?: array{ + * sort_field_name?: scalar|null, // Default: "sort" + * sort_direction_name?: scalar|null, // Default: "direction" + * filter_field_name?: scalar|null, // Default: "filterField" + * filter_value_name?: scalar|null, // Default: "filterValue" + * page_name?: scalar|null, // Default: "page" + * distinct?: bool, // Default: true + * page_out_of_range?: scalar|null, // Default: "ignore" + * default_limit?: scalar|null, // Default: 10 + * }, + * template?: array{ + * pagination?: scalar|null, // Default: "@KnpPaginator/Pagination/sliding.html.twig" + * rel_links?: scalar|null, // Default: "@KnpPaginator/Pagination/rel_links.html.twig" + * filtration?: scalar|null, // Default: "@KnpPaginator/Pagination/filtration.html.twig" + * sortable?: scalar|null, // Default: "@KnpPaginator/Pagination/sortable_link.html.twig" + * }, + * page_range?: scalar|null, // Default: 5 + * page_limit?: scalar|null, // Default: null + * convert_exception?: bool, // Default: false + * remove_first_page_param?: bool, // Default: false + * } + * @psalm-type DamaDoctrineTestConfig = array{ + * enable_static_connection?: mixed, // Default: true + * enable_static_meta_data_cache?: bool, // Default: true + * enable_static_query_cache?: bool, // Default: true + * connection_keys?: list, + * } + * @psalm-type SentryConfig = array{ + * dsn?: scalar|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, // Default: true + * register_error_handler?: bool, // Default: true + * logger?: scalar|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, + * prefixes?: list, + * sample_rate?: float, // 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, + * traces_sample_rate?: float, // 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|null, + * profiles_sample_rate?: float, // 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, + * attach_stacktrace?: bool, + * attach_metric_code_locations?: bool, + * context_lines?: int, + * environment?: scalar|null, // Default: "%kernel.environment%" + * logger?: scalar|null, + * spotlight?: bool, + * spotlight_url?: scalar|null, + * release?: scalar|null, // Default: "%env(default::SENTRY_RELEASE)%" + * server_name?: scalar|null, + * ignore_exceptions?: list, + * ignore_transactions?: list, + * before_send?: scalar|null, + * before_send_transaction?: scalar|null, + * before_send_check_in?: scalar|null, + * before_send_metrics?: scalar|null, + * before_send_log?: scalar|null, + * trace_propagation_targets?: mixed, + * tags?: array, + * error_types?: scalar|null, + * max_breadcrumbs?: int, + * before_breadcrumb?: mixed, + * in_app_exclude?: list, + * in_app_include?: list, + * send_default_pii?: bool, + * max_value_length?: int, + * transport?: scalar|null, + * http_client?: scalar|null, + * http_proxy?: scalar|null, + * http_proxy_authentication?: scalar|null, + * http_connect_timeout?: float, // 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, // The maximum execution time for the request+response as a whole. It works only when using the default transport. + * http_ssl_verify_peer?: bool, + * http_compression?: bool, + * capture_silenced_errors?: bool, + * max_request_body_size?: "none"|"small"|"medium"|"always", + * class_serializers?: array, + * }, + * messenger?: bool|array{ + * enabled?: bool, // Default: false + * capture_soft_fails?: bool, // Default: true + * isolate_breadcrumbs_by_message?: bool, // Default: false + * }, + * tracing?: bool|array{ + * enabled?: bool, // Default: true + * dbal?: bool|array{ + * enabled?: bool, // Default: true + * connections?: list, + * }, + * twig?: bool|array{ + * enabled?: bool, // Default: true + * }, + * cache?: bool|array{ + * enabled?: bool, // Default: true + * }, + * http_client?: bool|array{ + * enabled?: bool, // Default: true + * }, + * console?: array{ + * excluded_commands?: list, + * }, + * }, + * } + * @psalm-type ConfigType = array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * doctrine?: DoctrineConfig, + * jms_serializer?: JmsSerializerConfig, + * nelmio_api_doc?: NelmioApiDocConfig, + * monolog?: MonologConfig, + * framework?: FrameworkConfig, + * twig?: TwigConfig, + * security?: SecurityConfig, + * fos_rest?: FosRestConfig, + * doctrine_migrations?: DoctrineMigrationsConfig, + * twig_extra?: TwigExtraConfig, + * nelmio_cors?: NelmioCorsConfig, + * knp_paginator?: KnpPaginatorConfig, + * "when@dev"?: array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * doctrine?: DoctrineConfig, + * jms_serializer?: JmsSerializerConfig, + * nelmio_api_doc?: NelmioApiDocConfig, + * monolog?: MonologConfig, + * framework?: FrameworkConfig, + * twig?: TwigConfig, + * security?: SecurityConfig, + * fos_rest?: FosRestConfig, + * web_profiler?: WebProfilerConfig, + * doctrine_migrations?: DoctrineMigrationsConfig, + * debug?: DebugConfig, + * maker?: MakerConfig, + * twig_extra?: TwigExtraConfig, + * nelmio_cors?: NelmioCorsConfig, + * knp_paginator?: KnpPaginatorConfig, + * }, + * "when@prod"?: array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * doctrine?: DoctrineConfig, + * jms_serializer?: JmsSerializerConfig, + * nelmio_api_doc?: NelmioApiDocConfig, + * monolog?: MonologConfig, + * framework?: FrameworkConfig, + * twig?: TwigConfig, + * security?: SecurityConfig, + * fos_rest?: FosRestConfig, + * doctrine_migrations?: DoctrineMigrationsConfig, + * twig_extra?: TwigExtraConfig, + * sentry?: SentryConfig, + * nelmio_cors?: NelmioCorsConfig, + * knp_paginator?: KnpPaginatorConfig, + * }, + * "when@test"?: array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * doctrine?: DoctrineConfig, + * jms_serializer?: JmsSerializerConfig, + * nelmio_api_doc?: NelmioApiDocConfig, + * monolog?: MonologConfig, + * framework?: FrameworkConfig, + * twig?: TwigConfig, + * security?: SecurityConfig, + * fos_rest?: FosRestConfig, + * web_profiler?: WebProfilerConfig, + * doctrine_migrations?: DoctrineMigrationsConfig, + * debug?: DebugConfig, + * dama_doctrine_test?: DamaDoctrineTestConfig, + * twig_extra?: TwigExtraConfig, + * nelmio_cors?: NelmioCorsConfig, + * knp_paginator?: KnpPaginatorConfig, + * }, + * ..., + * }> + * } + */ +final class App +{ + /** + * @param ConfigType $config + * + * @psalm-return ConfigType + */ + public static function config(array $config): array + { + return AppReference::config($config); + } +} + +namespace Symfony\Component\Routing\Loader\Configurator; + +/** + * This class provides array-shapes for configuring the routes of an application. + * + * Example: + * + * ```php + * // config/routes.php + * namespace Symfony\Component\Routing\Loader\Configurator; + * + * return Routes::config([ + * 'controllers' => [ + * 'resource' => 'routing.controllers', + * ], + * ]); + * ``` + * + * @psalm-type RouteConfig = array{ + * path: string|array, + * controller?: string, + * methods?: string|list, + * requirements?: array, + * defaults?: array, + * options?: array, + * host?: string|array, + * schemes?: string|list, + * condition?: string, + * locale?: string, + * format?: string, + * utf8?: bool, + * stateless?: bool, + * } + * @psalm-type ImportConfig = array{ + * resource: string, + * type?: string, + * exclude?: string|list, + * prefix?: string|array, + * name_prefix?: string, + * trailing_slash_on_root?: bool, + * controller?: string, + * methods?: string|list, + * requirements?: array, + * defaults?: array, + * options?: array, + * host?: string|array, + * schemes?: string|list, + * condition?: string, + * locale?: string, + * format?: string, + * utf8?: bool, + * stateless?: bool, + * } + * @psalm-type AliasConfig = array{ + * alias: string, + * deprecated?: array{package:string, version:string, message?:string}, + * } + * @psalm-type RoutesConfig = array{ + * "when@dev"?: array, + * "when@prod"?: array, + * "when@test"?: array, + * ... + * } + */ +final class Routes +{ + /** + * @param RoutesConfig $config + * + * @psalm-return RoutesConfig + */ + public static function config(array $config): array + { + return $config; + } +} diff --git a/webapp/config/routes/framework.yaml b/webapp/config/routes/framework.yaml index 0fc74bbac4..bc1feace13 100644 --- a/webapp/config/routes/framework.yaml +++ b/webapp/config/routes/framework.yaml @@ -1,4 +1,4 @@ when@dev: _errors: - resource: '@FrameworkBundle/Resources/config/routing/errors.xml' + resource: '@FrameworkBundle/Resources/config/routing/errors.php' prefix: /_error diff --git a/webapp/config/routes/web_profiler.yaml b/webapp/config/routes/web_profiler.yaml index 8d85319fd8..b3b7b4b0e0 100644 --- a/webapp/config/routes/web_profiler.yaml +++ b/webapp/config/routes/web_profiler.yaml @@ -1,8 +1,8 @@ when@dev: web_profiler_wdt: - resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' + resource: '@WebProfilerBundle/Resources/config/routing/wdt.php' prefix: /_wdt web_profiler_profiler: - resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' + resource: '@WebProfilerBundle/Resources/config/routing/profiler.php' prefix: /_profiler diff --git a/webapp/config/services.yaml b/webapp/config/services.yaml index 2ae2a05c43..24c3f4d419 100644 --- a/webapp/config/services.yaml +++ b/webapp/config/services.yaml @@ -27,5 +27,4 @@ services: exclude: - '../src/DependencyInjection' - '../src/Entity' - - '../src/Migrations' - '../src/Kernel.php' diff --git a/webapp/migrations/Version20190803123217.php b/webapp/migrations/Version20190803123217.php index 3adaacdf0e..e13461cabb 100644 --- a/webapp/migrations/Version20190803123217.php +++ b/webapp/migrations/Version20190803123217.php @@ -4,8 +4,6 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerAwareTrait; final class Version20190803123217 extends AbstractMigration { @@ -22,7 +20,7 @@ public function getDescription(): string public function up(Schema $schema): void { $this->skipIf( - $this->connection->getSchemaManager()->tablesExist(['contest']), + $this->connection->createSchemaManager()->tablesExist(['contest']), 'table contest already exists' ); @@ -39,7 +37,7 @@ public function down(Schema $schema): void ); } - protected function createTables() + protected function createTables(): void { // Table structure for table `auditlog` $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); // We'll add some foreign key constraints later. First remove broken // references so that adding those constraints won't fail. diff --git a/webapp/migrations/Version20190906120011.php b/webapp/migrations/Version20190906120011.php index 89eb5a6fb7..3e5aa53ace 100644 --- a/webapp/migrations/Version20190906120011.php +++ b/webapp/migrations/Version20190906120011.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -24,7 +25,7 @@ public function getDescription() : string public function up(Schema $schema) : void { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE contestteamcategory (cid INT UNSIGNED NOT NULL COMMENT \'Contest ID\', categoryid INT UNSIGNED NOT NULL COMMENT \'Team category ID\', INDEX IDX_51A2DDC44B30D9C4 (cid), INDEX IDX_51A2DDC49B32FD3 (categoryid), PRIMARY KEY(cid, categoryid)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); $this->addSql('ALTER TABLE contestteamcategory ADD CONSTRAINT FK_51A2DDC44B30D9C4 FOREIGN KEY (cid) REFERENCES contest (cid) ON DELETE CASCADE'); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP TABLE contestteamcategory'); } diff --git a/webapp/migrations/Version20190922140905.php b/webapp/migrations/Version20190922140905.php index fbb44f970e..9861aa8021 100644 --- a/webapp/migrations/Version20190922140905.php +++ b/webapp/migrations/Version20190922140905.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging_run_output ADD metadata LONGBLOB DEFAULT NULL COMMENT \'Judging metadata(DC2Type:blobtext)\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging_run_output DROP metadata'); } diff --git a/webapp/migrations/Version20190923184715.php b/webapp/migrations/Version20190923184715.php index 45017eb671..cb24b7a79c 100644 --- a/webapp/migrations/Version20190923184715.php +++ b/webapp/migrations/Version20190923184715.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE testcase ADD orig_input_filename VARCHAR(255) DEFAULT NULL COMMENT \'Original basename of the input file.\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE testcase DROP orig_input_filename'); } diff --git a/webapp/migrations/Version20191031203138.php b/webapp/migrations/Version20191031203138.php index 00cebcd6d3..677acb5e23 100644 --- a/webapp/migrations/Version20191031203138.php +++ b/webapp/migrations/Version20191031203138.php @@ -7,16 +7,12 @@ use App\Entity\Language; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerAwareTrait; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20191031203138 extends AbstractMigration implements ContainerAwareInterface +final class Version20191031203138 extends AbstractMigration { - use ContainerAwareTrait; - public function isTransactional(): bool { return false; diff --git a/webapp/migrations/Version20191119183145.php b/webapp/migrations/Version20191119183145.php index 66a7fdd43c..648c21103f 100644 --- a/webapp/migrations/Version20191119183145.php +++ b/webapp/migrations/Version20191119183145.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE INDEX endpoint ON event (cid, endpointtype, endpointid)'); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX endpoint ON event'); } diff --git a/webapp/migrations/Version20200111104226.php b/webapp/migrations/Version20200111104226.php index 706f6438a8..f6aeeb1e56 100644 --- a/webapp/migrations/Version20200111104226.php +++ b/webapp/migrations/Version20200111104226.php @@ -4,18 +4,18 @@ namespace DoctrineMigrations; -use App\Service\ConfigurationService; +use App\Migrations\Factory\ConfigurationServiceAwareInterface; +use App\Migrations\Factory\ConfigurationServiceAwareTrait; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerAwareTrait; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20200111104226 extends AbstractMigration implements ContainerAwareInterface +final class Version20200111104226 extends AbstractMigration implements ConfigurationServiceAwareInterface { - use ContainerAwareTrait; + use ConfigurationServiceAwareTrait; public function isTransactional(): bool { @@ -30,7 +30,7 @@ public function getDescription(): string public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX public ON configuration'); @@ -40,7 +40,7 @@ public function up(Schema $schema): void public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE configuration @@ -51,8 +51,7 @@ public function down(Schema $schema): void $this->addSql('CREATE INDEX public ON configuration (public)'); // We also need to add back the type, category, public and description values - $configService = $this->container->get(ConfigurationService::class); - $specs = $configService->getConfigSpecification(); + $specs = $this->configurationService->getConfigSpecification(); foreach ($specs as $name => $spec) { $this->addSql( 'UPDATE configuration SET type = :type, category = :category, public = :public, description = :description WHERE name = :name', diff --git a/webapp/migrations/Version20200111104415.php b/webapp/migrations/Version20200111104415.php index 861f19d6e9..29b295a996 100644 --- a/webapp/migrations/Version20200111104415.php +++ b/webapp/migrations/Version20200111104415.php @@ -4,18 +4,18 @@ namespace DoctrineMigrations; +use App\Migrations\Factory\ConfigurationServiceAwareInterface; +use App\Migrations\Factory\ConfigurationServiceAwareTrait; use App\Service\ConfigurationService; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerAwareTrait; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20200111104415 extends AbstractMigration implements ContainerAwareInterface +final class Version20200111104415 extends AbstractMigration implements ConfigurationServiceAwareInterface { - use ContainerAwareTrait; + use ConfigurationServiceAwareTrait; public function isTransactional(): bool { @@ -29,9 +29,8 @@ public function getDescription(): string public function up(Schema $schema): void { - $configService = $this->container->get(ConfigurationService::class); - $specs = $configService->getConfigSpecification(); - $allConfig = $configService->all(); + $specs = $this->configurationService->getConfigSpecification(); + $allConfig = $this->configurationService->all(); foreach ($allConfig as $name => $value) { if ($value == ($specs[$name]->default_value ?? null)) { @@ -45,8 +44,7 @@ public function up(Schema $schema): void public function down(Schema $schema): void { - $configService = $this->container->get(ConfigurationService::class); - $allConfig = $configService->all(); + $allConfig = $this->configurationService->all(); foreach ($allConfig as $name => $value) { $this->addSql( diff --git a/webapp/migrations/Version20200118092658.php b/webapp/migrations/Version20200118092658.php index 6da24b2c37..f34c675570 100644 --- a/webapp/migrations/Version20200118092658.php +++ b/webapp/migrations/Version20200118092658.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX externalid ON team'); $this->addSql('ALTER TABLE team CHANGE externalid icpcid VARCHAR(255) DEFAULT NULL COLLATE utf8mb4_bin COMMENT \'Team ID in the ICPC system\''); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX icpcid ON team'); $this->addSql('ALTER TABLE team CHANGE icpcid externalid VARCHAR(255) DEFAULT NULL COLLATE utf8mb4_bin COMMENT \'Team ID in an external system\''); diff --git a/webapp/migrations/Version20200118122750.php b/webapp/migrations/Version20200118122750.php index c4fadef2af..65cd3514ef 100644 --- a/webapp/migrations/Version20200118122750.php +++ b/webapp/migrations/Version20200118122750.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE team ADD display_name VARCHAR(255) DEFAULT NULL COLLATE utf8mb4_bin COMMENT \'Team display name\' AFTER name'); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE team DROP display_name'); } diff --git a/webapp/migrations/Version20200131064449.php b/webapp/migrations/Version20200131064449.php index 455fde7fa6..88fa2451c9 100644 --- a/webapp/migrations/Version20200131064449.php +++ b/webapp/migrations/Version20200131064449.php @@ -4,17 +4,12 @@ namespace DoctrineMigrations; -use App\Entity\Configuration; -use App\Entity\TeamCategory; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerAwareTrait; -final class Version20200131064449 extends AbstractMigration implements ContainerAwareInterface +final class Version20200131064449 extends AbstractMigration { - use ContainerAwareTrait; - public function isTransactional(): bool { return false; @@ -27,7 +22,7 @@ public function getDescription() : string public function up(Schema $schema) : void { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); // Note: can't use ConfigurationService::get on 'registration_category_name' because the specification has been removed from db-config.yaml $registrationCategoryNameConfig = $this->connection->fetchAssociative('SELECT * FROM configuration WHERE name = :registration_category_name', ['registration_category_name' => 'registration_category_name']); @@ -50,7 +45,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $selfRegistrationCategories = $this->connection->fetchAllAssociative('SELECT * FROM team_category WHERE allow_self_registration = 1 ORDER BY sortorder'); diff --git a/webapp/migrations/Version20200425120051.php b/webapp/migrations/Version20200425120051.php index b0ff3e3372..cd5a84167b 100644 --- a/webapp/migrations/Version20200425120051.php +++ b/webapp/migrations/Version20200425120051.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE testcase ADD deleted TINYINT(1) DEFAULT \'0\' NOT NULL COMMENT \'Deleted testcases are kept for referential integrity.\''); $this->addSql('ALTER TABLE testcase CHANGE probid probid INT UNSIGNED DEFAULT NULL COMMENT \'Corresponding problem ID\''); @@ -34,7 +35,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE testcase DROP deleted, CHANGE probid probid INT UNSIGNED NOT NULL COMMENT \'Corresponding problem ID\''); } diff --git a/webapp/migrations/Version20200501102548.php b/webapp/migrations/Version20200501102548.php index de61aefcc5..ffb855c594 100644 --- a/webapp/migrations/Version20200501102548.php +++ b/webapp/migrations/Version20200501102548.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE rejudging ADD auto_apply TINYINT(1) DEFAULT \'0\' NOT NULL COMMENT \'If set, judgings are accepted automatically.\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE rejudging DROP auto_apply'); } diff --git a/webapp/migrations/Version20200516101037.php b/webapp/migrations/Version20200516101037.php index a40dfc017a..6cc665eb19 100644 --- a/webapp/migrations/Version20200516101037.php +++ b/webapp/migrations/Version20200516101037.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription(): string public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, "Migration can only be executed safely on 'mysql'."); $this->addSql("ALTER TABLE external_judgement @@ -38,7 +39,7 @@ public function up(Schema $schema): void public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, "Migration can only be executed safely on 'mysql'."); $this->addSql('DROP INDEX verified ON external_judgement'); diff --git a/webapp/migrations/Version20201107151003.php b/webapp/migrations/Version20201107151003.php index 447c44c9be..a1d1a342a3 100644 --- a/webapp/migrations/Version20201107151003.php +++ b/webapp/migrations/Version20201107151003.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE user CHANGE teamid teamid INT UNSIGNED DEFAULT NULL COMMENT \'Team associated with this user\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE user CHANGE teamid teamid INT UNSIGNED DEFAULT NULL COMMENT \'Team associated with\''); } diff --git a/webapp/migrations/Version20201110113446.php b/webapp/migrations/Version20201110113446.php index f80027d9f9..f796dd7795 100644 --- a/webapp/migrations/Version20201110113446.php +++ b/webapp/migrations/Version20201110113446.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE language CHANGE compile_script compile_script VARCHAR(32) DEFAULT NULL COMMENT \'Executable ID (string)\''); $this->addSql('ALTER TABLE problem CHANGE special_run special_run VARCHAR(32) DEFAULT NULL COMMENT \'Executable ID (string)\', CHANGE special_compare special_compare VARCHAR(32) DEFAULT NULL COMMENT \'Executable ID (string)\''); @@ -49,7 +50,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE balloon CHANGE submitid submitid INT UNSIGNED NOT NULL COMMENT \'Submission for which balloon was earned\''); $this->addSql('ALTER TABLE clarification CHANGE probid probid INT UNSIGNED DEFAULT NULL COMMENT \'Problem associated to this clarification\', CHANGE cid cid INT UNSIGNED NOT NULL COMMENT \'Contest ID\', CHANGE respid respid INT UNSIGNED DEFAULT NULL COMMENT \'In reply to clarification ID\', CHANGE sender sender INT UNSIGNED DEFAULT NULL COMMENT \'Team ID, null means jury\', CHANGE recipient recipient INT UNSIGNED DEFAULT NULL COMMENT \'Team ID, null means to jury or to all\''); diff --git a/webapp/migrations/Version20201113094653.php b/webapp/migrations/Version20201113094653.php index 22ecf9dbf1..0f15b05be8 100644 --- a/webapp/migrations/Version20201113094653.php +++ b/webapp/migrations/Version20201113094653.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE problem_attachment_content (attachmentid INT UNSIGNED NOT NULL COMMENT \'Attachment ID\', content LONGBLOB NOT NULL COMMENT \'Attachment content(DC2Type:blobtext)\', PRIMARY KEY(attachmentid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Stores contents of problem attachments\' '); $this->addSql('CREATE TABLE problem_attachment (attachmentid INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Attachment ID\', probid INT UNSIGNED DEFAULT NULL COMMENT \'Problem ID\', name VARCHAR(255) NOT NULL COMMENT \'Filename of attachment\', type VARCHAR(4) NOT NULL COMMENT \'File type of attachment\', INDEX IDX_317299FEEF049279 (probid), INDEX name (attachmentid, name(190)), PRIMARY KEY(attachmentid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Attachments belonging to problems\' '); @@ -36,7 +37,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE problem_attachment_content DROP FOREIGN KEY FK_C097D9BF4707030C'); $this->addSql('DROP TABLE problem_attachment_content'); diff --git a/webapp/migrations/Version20201122080505.php b/webapp/migrations/Version20201122080505.php index ed347c61de..c27215d15a 100644 --- a/webapp/migrations/Version20201122080505.php +++ b/webapp/migrations/Version20201122080505.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX `rank` ON testcase'); $this->addSql('ALTER TABLE testcase CHANGE `rank` ranknumber INT UNSIGNED NOT NULL COMMENT \'Determines order of the testcases in judging\''); @@ -38,7 +39,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX rankindex ON submission_file'); $this->addSql('ALTER TABLE submission_file CHANGE ranknumber `rank` INT UNSIGNED NOT NULL COMMENT \'Order of the submission files, zero-indexed\''); diff --git a/webapp/migrations/Version20201219154651.php b/webapp/migrations/Version20201219154651.php index ebb70c36b3..ac3fff1a4c 100644 --- a/webapp/migrations/Version20201219154651.php +++ b/webapp/migrations/Version20201219154651.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription(): string public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE judgetask (judgetaskid INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Judgetask ID\', judgehostid INT UNSIGNED DEFAULT NULL COMMENT \'Judgehost ID\', type ENUM(\'judging_run\', \'generic_task\', \'config_check\', \'debug_info\', \'prefetch\') DEFAULT \'judging_run\' NOT NULL COMMENT \'Type of the judge task.(DC2Type:judge_task_type)\', priority INT NOT NULL COMMENT \'Priority; negative means higher priority\', jobid INT UNSIGNED DEFAULT NULL COMMENT \'All judgetasks with the same jobid belong together.\', submitid INT UNSIGNED DEFAULT NULL COMMENT \'Submission ID being judged\', compile_script_id INT UNSIGNED DEFAULT NULL COMMENT \'Compile script ID\', run_script_id INT UNSIGNED DEFAULT NULL COMMENT \'Run script ID\', compare_script_id INT UNSIGNED DEFAULT NULL COMMENT \'Compare script ID\', testcase_id INT UNSIGNED DEFAULT NULL COMMENT \'Testcase ID\', compile_config LONGTEXT DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'The compile config as JSON-blob.\', run_config LONGTEXT DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'The run config as JSON-blob.\', compare_config LONGTEXT DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'The compare config as JSON-blob.\', valid TINYINT(1) DEFAULT \'1\' NOT NULL COMMENT \'Only handed out if still valid.\', starttime NUMERIC(32, 9) UNSIGNED DEFAULT NULL COMMENT \'Time the judgetask was started\', PRIMARY KEY(judgetaskid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Individual judge tasks.\' '); $this->addSql('CREATE TABLE executable_file (execfileid INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Executable file ID\', immutable_execid INT UNSIGNED DEFAULT NULL COMMENT \'ID\', filename VARCHAR(255) NOT NULL COMMENT \'Filename as uploaded\', ranknumber INT UNSIGNED NOT NULL COMMENT \'Order of the executable files, zero-indexed\', file_content LONGBLOB NOT NULL COMMENT \'Full file content(DC2Type:blobtext)\', hash VARCHAR(32) DEFAULT NULL COMMENT \'hash of the content\', is_executable TINYINT(1) DEFAULT \'0\' NOT NULL COMMENT \'Whether this file gets an executable bit.\', INDEX immutable_execid (immutable_execid), UNIQUE INDEX rankindex (immutable_execid, ranknumber), UNIQUE INDEX filename (immutable_execid, filename(190)), PRIMARY KEY(execfileid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Files associated to an executable\' '); diff --git a/webapp/migrations/Version20210407120356.php b/webapp/migrations/Version20210407120356.php index 27543fba5e..3b39f431dd 100644 --- a/webapp/migrations/Version20210407120356.php +++ b/webapp/migrations/Version20210407120356.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; use ZipArchive; @@ -26,7 +27,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); if ($schema->getTable('executable')->hasColumn('zipfile')) { $oldRows = $this->connection->executeQuery('SELECT execid, zipfile FROM executable')->fetchAllAssociative(); diff --git a/webapp/migrations/Version20210611141202.php b/webapp/migrations/Version20210611141202.php index f26c617423..8e144fff8a 100644 --- a/webapp/migrations/Version20210611141202.php +++ b/webapp/migrations/Version20210611141202.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE contestteamcategoryformedals (cid INT UNSIGNED NOT NULL COMMENT \'Contest ID\', categoryid INT UNSIGNED NOT NULL COMMENT \'Team category ID\', INDEX IDX_40B1F5544B30D9C4 (cid), INDEX IDX_40B1F5549B32FD3 (categoryid), PRIMARY KEY(cid, categoryid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('ALTER TABLE contestteamcategoryformedals ADD CONSTRAINT FK_40B1F5544B30D9C4 FOREIGN KEY (cid) REFERENCES contest (cid) ON DELETE CASCADE'); @@ -36,7 +37,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP TABLE contestteamcategoryformedals'); $this->addSql('ALTER TABLE contest DROP medals_enabled, DROP gold_medals, DROP silver_medals, DROP bronze_medals'); diff --git a/webapp/migrations/Version20210705095555.php b/webapp/migrations/Version20210705095555.php index d3e8219b2b..a348451d28 100644 --- a/webapp/migrations/Version20210705095555.php +++ b/webapp/migrations/Version20210705095555.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging DROP judgehost'); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging ADD judgehost VARCHAR(64) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Resolvable hostname of judgehost\''); } diff --git a/webapp/migrations/Version20210806180453.php b/webapp/migrations/Version20210806180453.php index d0e401abfd..6f5cf755b3 100644 --- a/webapp/migrations/Version20210806180453.php +++ b/webapp/migrations/Version20210806180453.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE submission ADD userid INT UNSIGNED DEFAULT NULL COMMENT \'User ID\' AFTER teamid'); $this->addSql('ALTER TABLE submission ADD CONSTRAINT FK_DB055AF3F132696E FOREIGN KEY (userid) REFERENCES user (userid) ON DELETE CASCADE'); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE submission DROP FOREIGN KEY FK_DB055AF3F132696E'); $this->addSql('DROP INDEX userid ON submission'); diff --git a/webapp/migrations/Version20210813195818.php b/webapp/migrations/Version20210813195818.php index 25bc23427b..ec536fc504 100644 --- a/webapp/migrations/Version20210813195818.php +++ b/webapp/migrations/Version20210813195818.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgehost DROP FOREIGN KEY judgehost_ibfk_1'); $this->addSql('DROP TABLE judgehost_restriction'); @@ -36,7 +37,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE judgehost_restriction (restrictionid INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Judgehost restriction ID\', name VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Descriptive name\', restrictions LONGTEXT CHARACTER SET utf8mb4 DEFAULT \'NULL\' COLLATE `utf8mb4_unicode_ci` COMMENT \'JSON-encoded restrictions(DC2Type:json)\', PRIMARY KEY(restrictionid)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB COMMENT = \'Restrictions for judgehosts\' '); $this->addSql('ALTER TABLE judgehost ADD restrictionid INT UNSIGNED DEFAULT NULL COMMENT \'Judgehost restriction ID\''); diff --git a/webapp/migrations/Version20210823160249.php b/webapp/migrations/Version20210823160249.php index 737c9944c5..a2a339c596 100644 --- a/webapp/migrations/Version20210823160249.php +++ b/webapp/migrations/Version20210823160249.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging DROP FOREIGN KEY judging_ibfk_3'); $this->addSql('DROP INDEX judgehostid ON judging'); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging ADD judgehostid INT UNSIGNED DEFAULT NULL COMMENT \'Judgehost ID\''); $this->addSql('ALTER TABLE judging ADD CONSTRAINT judging_ibfk_3 FOREIGN KEY (judgehostid) REFERENCES judgehost (judgehostid)'); diff --git a/webapp/migrations/Version20210829113200.php b/webapp/migrations/Version20210829113200.php index 1d3fa0d8a0..29e6e91a19 100644 --- a/webapp/migrations/Version20210829113200.php +++ b/webapp/migrations/Version20210829113200.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE debug_package (debug_package_id INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Debug Package ID\', judgingid INT UNSIGNED DEFAULT NULL COMMENT \'Judging ID\', judgehostid INT UNSIGNED DEFAULT NULL COMMENT \'Judgehost ID\', filename VARCHAR(255) NOT NULL COMMENT \'Name of the file where we stored the debug package.\', INDEX IDX_9E17399BE0E4FC3E (judgehostid), INDEX judgingid (judgingid), PRIMARY KEY(debug_package_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Debug packages.\' '); $this->addSql('ALTER TABLE debug_package ADD CONSTRAINT FK_9E17399B5D5FEA72 FOREIGN KEY (judgingid) REFERENCES judging (judgingid) ON DELETE CASCADE'); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP TABLE debug_package'); } diff --git a/webapp/migrations/Version20210914192815.php b/webapp/migrations/Version20210914192815.php index 065a7ee625..151ce778fa 100644 --- a/webapp/migrations/Version20210914192815.php +++ b/webapp/migrations/Version20210914192815.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging ADD errorid INT UNSIGNED DEFAULT NULL COMMENT \'Internal error ID\''); $this->addSql('ALTER TABLE judging ADD CONSTRAINT FK_4CA80CED4BCA8D9D FOREIGN KEY (errorid) REFERENCES internal_error (errorid) ON DELETE SET NULL'); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging DROP FOREIGN KEY FK_4CA80CED4BCA8D9D'); $this->addSql('DROP INDEX IDX_4CA80CED4BCA8D9D ON judging'); diff --git a/webapp/migrations/Version20210929123058.php b/webapp/migrations/Version20210929123058.php index 0d652dee74..c3b99071b8 100644 --- a/webapp/migrations/Version20210929123058.php +++ b/webapp/migrations/Version20210929123058.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgetask ADD uuid VARCHAR(255) DEFAULT NULL COMMENT \'Optional UUID for the associated judging, used for caching.\''); $this->addSql('ALTER TABLE judging ADD uuid VARCHAR(255) NOT NULL COMMENT \'UUID, to make caching of compilation results safe.\''); @@ -34,7 +35,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgetask DROP uuid'); $this->addSql('ALTER TABLE judging DROP uuid'); diff --git a/webapp/migrations/Version20211001213842.php b/webapp/migrations/Version20211001213842.php index eff0af1608..d53d804894 100644 --- a/webapp/migrations/Version20211001213842.php +++ b/webapp/migrations/Version20211001213842.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgetask ADD testcase_hash VARCHAR(100) DEFAULT NULL COMMENT \'Testcase Hash\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgetask DROP testcase_hash'); } diff --git a/webapp/migrations/Version20211002100928.php b/webapp/migrations/Version20211002100928.php index 66ff39939a..ad146fa14b 100644 --- a/webapp/migrations/Version20211002100928.php +++ b/webapp/migrations/Version20211002100928.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE queuetask (queuetaskid INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Queuetask ID\', teamid INT UNSIGNED DEFAULT NULL COMMENT \'Team ID\', jobid INT UNSIGNED DEFAULT NULL COMMENT \'All queuetasks with the same jobid belong together.\', priority INT NOT NULL COMMENT \'Priority; negative means higher priority\', teampriority INT NOT NULL COMMENT \'Team Priority; somewhat magic, lower implies higher priority.\', starttime NUMERIC(32, 9) UNSIGNED DEFAULT NULL COMMENT \'Time started work\', INDEX queuetaskid (queuetaskid), INDEX jobid (jobid), INDEX priority (priority), INDEX teampriority (teampriority), INDEX teamid (teamid), INDEX starttime (starttime), PRIMARY KEY(queuetaskid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Work items.\' '); $this->addSql('ALTER TABLE queuetask ADD CONSTRAINT FK_45E85FF84DD6ABF3 FOREIGN KEY (teamid) REFERENCES team (teamid) ON DELETE CASCADE'); @@ -34,7 +35,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP TABLE queuetask'); } diff --git a/webapp/migrations/Version20211006161627.php b/webapp/migrations/Version20211006161627.php index 8fd1bca943..0672433158 100644 --- a/webapp/migrations/Version20211006161627.php +++ b/webapp/migrations/Version20211006161627.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging ADD metadata LONGBLOB DEFAULT NULL COMMENT \'Compilation metadata(DC2Type:blobtext)\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judging DROP metadata'); } diff --git a/webapp/migrations/Version20211208190658.php b/webapp/migrations/Version20211208190658.php index 75bb736d25..f8aa4fbe4d 100644 --- a/webapp/migrations/Version20211208190658.php +++ b/webapp/migrations/Version20211208190658.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE auditlog CHANGE action action VARCHAR(128) DEFAULT NULL COMMENT \'Description of action performed\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE auditlog CHANGE action action VARCHAR(64) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Description of action performed\''); } diff --git a/webapp/migrations/Version20220206094350.php b/webapp/migrations/Version20220206094350.php index 49f5866b7c..624da157b8 100644 --- a/webapp/migrations/Version20220206094350.php +++ b/webapp/migrations/Version20220206094350.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE auditlog CHANGE datatype datatype VARCHAR(32) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Reference to DB table associated to this entry\', CHANGE action action VARCHAR(128) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Description of action performed\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE auditlog CHANGE datatype datatype VARCHAR(32) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Reference to DB table associated to this entry\', CHANGE action action VARCHAR(128) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci` COMMENT \'Description of action performed\''); } diff --git a/webapp/migrations/Version20220206113543.php b/webapp/migrations/Version20220206113543.php index 3768731da1..9f178c431c 100644 --- a/webapp/migrations/Version20220206113543.php +++ b/webapp/migrations/Version20220206113543.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE contestteamcategoryformedals DROP FOREIGN KEY FK_40B1F5544B30D9C4'); $this->addSql('ALTER TABLE contestteamcategoryformedals DROP FOREIGN KEY FK_40B1F5549B32FD3'); @@ -40,7 +41,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE contestteamcategoryformedals DROP FOREIGN KEY FK_CC3496DE4B30D9C4'); $this->addSql('ALTER TABLE contestteamcategoryformedals DROP FOREIGN KEY FK_CC3496DE9B32FD3'); diff --git a/webapp/migrations/Version20220208180025.php b/webapp/migrations/Version20220208180025.php index 36241a8547..5a2b26d2e2 100644 --- a/webapp/migrations/Version20220208180025.php +++ b/webapp/migrations/Version20220208180025.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgehost CHANGE active enabled TINYINT(1) DEFAULT \'1\' NOT NULL COMMENT \'Should this host take on judgings?\''); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE judgehost CHANGE enabled active TINYINT(1) DEFAULT \'1\' NOT NULL COMMENT \'Should this host take on judgings?\''); } diff --git a/webapp/migrations/Version20220210142638.php b/webapp/migrations/Version20220210142638.php index 3a402dfffd..4359d645df 100644 --- a/webapp/migrations/Version20220210142638.php +++ b/webapp/migrations/Version20220210142638.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE team_affiliation ADD icpcid VARCHAR(255) DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'External identifier from ICPC CMS\' AFTER `externalid`'); } @@ -33,7 +34,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE team_affiliation DROP icpcid'); } diff --git a/webapp/migrations/Version20220210155918.php b/webapp/migrations/Version20220210155918.php index 51fb244014..ef36d5cf2f 100644 --- a/webapp/migrations/Version20220210155918.php +++ b/webapp/migrations/Version20220210155918.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('ALTER TABLE team_category ADD externalid VARCHAR(255) DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'Team category ID in an external system\' AFTER `categoryid`, ADD icpcid VARCHAR(255) DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'External identifier from ICPC CMS\' AFTER `externalid`'); $this->addSql('CREATE UNIQUE INDEX externalid ON team_category (externalid(190))'); @@ -35,7 +36,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX externalid ON team_category'); $this->addSql('ALTER TABLE team_category DROP externalid, DROP icpcid'); diff --git a/webapp/migrations/Version20220210171746.php b/webapp/migrations/Version20220210171746.php index d8015fd25a..9c658ff2b2 100644 --- a/webapp/migrations/Version20220210171746.php +++ b/webapp/migrations/Version20220210171746.php @@ -4,6 +4,7 @@ namespace DoctrineMigrations; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; @@ -25,7 +26,7 @@ public function getDescription() : string public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX icpcid ON team'); $this->addSql('ALTER TABLE team ADD externalid VARCHAR(255) DEFAULT NULL COLLATE `utf8mb4_bin` COMMENT \'Team affiliation ID in an external system\' AFTER `teamid`'); @@ -36,7 +37,7 @@ public function up(Schema $schema) : void public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->abortIf(!$this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform, 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP INDEX externalid ON team'); $this->addSql('ALTER TABLE team DROP externalid'); diff --git a/webapp/migrations/Version20240604202419.php b/webapp/migrations/Version20240604202419.php index aaed521051..0f5af49750 100644 --- a/webapp/migrations/Version20240604202419.php +++ b/webapp/migrations/Version20240604202419.php @@ -42,7 +42,7 @@ public function up(Schema $schema): void } } - protected function setExternalIds(string $table, string $column, string $prefix = '') + protected function setExternalIds(string $table, string $column, string $prefix = ''): void { $entries = $this->connection->fetchAllAssociative("SELECT $column FROM $table WHERE externalid IS NULL"); foreach ($entries as $entry) { diff --git a/webapp/phpstan.dist.neon b/webapp/phpstan.dist.neon index 52c70905c5..59ff819a1e 100644 --- a/webapp/phpstan.dist.neon +++ b/webapp/phpstan.dist.neon @@ -2,9 +2,8 @@ parameters: level: 6 paths: - src + - migrations - tests - excludePaths: - - src/Utils/Adminer.php ignoreErrors: - message: '#Method .* return type has no value type specified in iterable type array#' diff --git a/webapp/phpunit.xml.dist b/webapp/phpunit.xml.dist index 21b6388923..84027053cd 100644 --- a/webapp/phpunit.xml.dist +++ b/webapp/phpunit.xml.dist @@ -14,7 +14,7 @@ - + diff --git a/webapp/resources/functions.php b/webapp/resources/functions.php index d0147b5aa5..5fbb8baa0f 100644 --- a/webapp/resources/functions.php +++ b/webapp/resources/functions.php @@ -1,10 +1,86 @@ getDatabaseCredentials()['db']; + } + + public function databases($flush = true): array + { + return [$this->getDatabaseCredentials()['db']]; + } + + public function credentials(): array + { + ['host' => $host, 'user' => $user, 'pass' => $pass] = $this->getDatabaseCredentials(); + + return [$host, $user, $pass]; + } + + public function login($login, $password): bool + { + return true; + } + + public function tableName($tableStatus): string + { + return h($tableStatus['Name']); + } + + public function permanentLogin($create = false): string + { + return 'domjudge'; + } + + public function loginForm(): void + { + ['db' => $db, 'user' => $user] = $this->getDatabaseCredentials(); + echo ""; + echo ""; + echo ""; + echo "

\n"; + } + + /** + * @return array{host: string, db: string, user: string, pass: string} + */ + private function getDatabaseCredentials(): array + { + $host = $db = $user = $pass = null; + + // Load credentials from /dbpasswords.secret + $dbsecretsfile = $GLOBALS['etcDir'] . '/dbpasswords.secret'; + $db_credentials = file($dbsecretsfile); + foreach ($db_credentials as $line) { + if ($line[0] == '#') { + continue; + } + [$_, $host, $db, $user, $pass] = array_pad(explode(':', trim($line)), 6, null); + break; + } + + if ($host === null) { + throw new \LogicException("Can't get DB credentials"); + } + + return ['host' => $host, 'db' => $db, 'user' => $user, 'pass' => $pass]; + } + }; } } diff --git a/webapp/src/Command/AbstractCompareCommand.php b/webapp/src/Command/AbstractCompareCommand.php index 99c0d2cfc4..6d4f1734d6 100644 --- a/webapp/src/Command/AbstractCompareCommand.php +++ b/webapp/src/Command/AbstractCompareCommand.php @@ -5,8 +5,8 @@ use App\Service\Compare\AbstractCompareService; use App\Service\Compare\Message; use App\Service\Compare\MessageType; +use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; @@ -15,7 +15,7 @@ /** * @template T */ -abstract class AbstractCompareCommand extends Command +abstract class AbstractCompareCommand { /** * @param AbstractCompareService $compareService @@ -24,20 +24,18 @@ public function __construct( protected readonly SerializerInterface $serializer, protected AbstractCompareService $compareService ) { - parent::__construct(); } - protected function configure(): void - { - $this - ->addArgument('file1', InputArgument::REQUIRED, 'First file to compare') - ->addArgument('file2', InputArgument::REQUIRED, 'Second file to compare'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { + public function __invoke( + InputInterface $input, + OutputInterface $output, + #[Argument(description: 'First file to compare')] + string $file1, + #[Argument(description: 'Second file to compare')] + string $file2, + ): int { $style = new SymfonyStyle($input, $output); - $messages = $this->compareService->compareFiles($input->getArgument('file1'), $input->getArgument('file2')); + $messages = $this->compareService->compareFiles($file1, $file2); return $this->displayMessages($style, $messages) ?? Command::SUCCESS; } diff --git a/webapp/src/Command/CallApiActionCommand.php b/webapp/src/Command/CallApiActionCommand.php index 64a0fda581..b90121c7e0 100644 --- a/webapp/src/Command/CallApiActionCommand.php +++ b/webapp/src/Command/CallApiActionCommand.php @@ -6,11 +6,11 @@ use App\Service\DOMJudgeService; use App\Utils\Utils; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; @@ -20,65 +20,42 @@ name: 'api:call', description: 'Call the DOMjudge API directly. Note: this will use admin credentials' )] -class CallApiActionCommand extends Command +readonly class CallApiActionCommand { - public function __construct(protected readonly DOMJudgeService $dj, protected readonly EntityManagerInterface $em) - { - parent::__construct(); - } - - protected function configure(): void - { - $this - ->addArgument( - 'endpoint', - InputArgument::REQUIRED, - 'The API endpoint to call. For example `contests/3/teams`' - ) - ->addOption( - 'method', - 'm', - InputOption::VALUE_REQUIRED, - 'The HTTP method to use', - Request::METHOD_GET - ) - ->addOption( - 'data', - 'd', - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'POST data to use as key=value. Only allowed when the method is POST or PUT' - ) - ->addOption( - 'json', - 'j', - InputOption::VALUE_REQUIRED, - 'JSON body data to use. Only allowed when the method is POST or PUT' - ) - ->addOption( - 'file', - 'f', - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Files to use as field=filename. Only allowed when the method is POST or PUT' - ) - ->addOption( - 'user', - 'u', - InputOption::VALUE_REQUIRED, - 'User to use for API requests. If not given, the first admin user will be used' - ); - } + public function __construct( + protected DOMJudgeService $dj, + protected EntityManagerInterface $em + ) {} - protected function execute(InputInterface $input, OutputInterface $output): int - { - if (!in_array($input->getOption('method'), [Request::METHOD_GET, Request::METHOD_POST, Request::METHOD_PUT], true)) { + /** + * @param array $data + * @param array $file + */ + public function __invoke( + #[Argument(description: 'The API endpoint to call. For example `contests/3/teams`')] + string $endpoint, + InputInterface $input, + OutputInterface $output, + #[Option(description: 'POST data to use as key=value. Only allowed when the method is POST or PUT', shortcut: 'd')] + array $data = [], + #[Option(description: 'Files to use as field=filename. Only allowed when the method is POST or PUT', shortcut: 'f')] + array $file = [], + #[Option(description: 'User to use for API requests. If not given, the first admin user will be used', shortcut: 'u')] + ?string $user = null, + #[Option(description: 'JSON body data to use. Only allowed when the method is POST or PUT', shortcut: 'j')] + ?string $json = null, + #[Option(description: 'The HTTP method to use', shortcut: 'm')] + string $method = Request::METHOD_GET, + ): int { + if (!in_array($method, [Request::METHOD_GET, Request::METHOD_POST, Request::METHOD_PUT], true)) { $output->writeln('Error: only GET, POST and PUT methods are supported'); return Command::FAILURE; } - if ($input->getOption('user')) { + if ($user) { $user = $this->em ->getRepository(User::class) - ->findOneBy(['username' => $input->getOption('user')]); + ->findOneBy(['username' => $user]); if (!$user) { $output->writeln('Error: Provided user not found'); return Command::FAILURE; @@ -101,43 +78,43 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $data = []; + $jsonData = []; $files = []; - if (in_array($input->getOption('method'), [Request::METHOD_POST, Request::METHOD_PUT], true)) { - foreach ($input->getOption('data') as $dataItem) { + if (in_array($method, [Request::METHOD_POST, Request::METHOD_PUT], true)) { + foreach ($data as $dataItem) { $parts = explode('=', $dataItem, 2); if (count($parts) !== 2) { $output->writeln(sprintf('Error: data item %s is not in key=value format', $dataItem)); - return self::FAILURE; + return Command::FAILURE; } - $data[$parts[0]] = $parts[1]; + $jsonData[$parts[0]] = $parts[1]; } - if ($json = $input->getOption('json')) { - $data = array_merge($data, Utils::jsonDecode($json)); + if ($json) { + $jsonData = array_merge($jsonData, Utils::jsonDecode($json)); } - foreach ($input->getOption('file') as $fileItem) { + foreach ($file as $fileItem) { $parts = explode('=', $fileItem, 2); if (count($parts) !== 2) { $output->writeln(sprintf('Error: file item %s is not in key=value format', $fileItem)); - return self::FAILURE; + return Command::FAILURE; } if (!file_exists($parts[1])) { $output->writeln(sprintf('Error: file %s does not exist', $parts[1])); - return self::FAILURE; + return Command::FAILURE; } $files[$parts[0]] = new UploadedFile($parts[1], basename($parts[1]), mime_content_type($parts[1]), null, true); } } else { - if ($input->getOption('data')) { + if ($data) { $output->writeln('Error: data not allowed for GET methods.'); return Command::FAILURE; } - if ($input->getOption('file')) { + if ($file) { $output->writeln('Error: files not allowed for GET methods.'); return Command::FAILURE; } @@ -145,8 +122,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int try { $response = ''; - $this->dj->withAllRoles(function () use ($input, $data, $files, &$response) { - $response = $this->dj->internalApiRequest('/' . $input->getArgument('endpoint'), $input->getOption('method'), $data, $files, true); + $this->dj->withAllRoles(function () use ($method, $endpoint, $jsonData, $files, &$response): void { + $response = $this->dj->internalApiRequest('/' . $endpoint, $method, $jsonData, $files, true); }, $user); } catch (HttpException $e) { $output->writeln($e->getMessage()); diff --git a/webapp/src/Command/CheckDatabaseConfigurationDefaultValuesCommand.php b/webapp/src/Command/CheckDatabaseConfigurationDefaultValuesCommand.php index f213fdaede..60df1de62a 100644 --- a/webapp/src/Command/CheckDatabaseConfigurationDefaultValuesCommand.php +++ b/webapp/src/Command/CheckDatabaseConfigurationDefaultValuesCommand.php @@ -5,24 +5,20 @@ use App\Service\ConfigurationService; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; #[AsCommand( name: 'domjudge:db-config:check', description: 'Check if the default values of the database configuration are valid' )] -class CheckDatabaseConfigurationDefaultValuesCommand extends Command +class CheckDatabaseConfigurationDefaultValuesCommand { - public function __construct(protected readonly ConfigurationService $config, ?string $name = null) - { - parent::__construct($name); - } + public function __construct( + protected readonly ConfigurationService $config, + ) {} - protected function execute(InputInterface $input, OutputInterface $output): int + public function __invoke(SymfonyStyle $style): int { - $style = new SymfonyStyle($input, $output); $messages = []; foreach ($this->config->getConfigSpecification() as $specification) { $message = sprintf( diff --git a/webapp/src/Command/ImportEventFeedCommand.php b/webapp/src/Command/ImportEventFeedCommand.php index eee70cc16e..f490c32648 100644 --- a/webapp/src/Command/ImportEventFeedCommand.php +++ b/webapp/src/Command/ImportEventFeedCommand.php @@ -2,21 +2,23 @@ namespace App\Command; -use App\Controller\API\GeneralInfoController as GI; use App\Entity\Contest; use App\Entity\ExternalContestSource; use App\Entity\User; use App\Service\ConfigurationService; use App\Service\DOMJudgeService; use App\Service\ExternalContestSourceService; +use Doctrine\Bundle\DoctrineBundle\Middleware\DebugMiddleware; +use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface; +use Doctrine\DBAL\Logging\Middleware; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NonUniqueResultException; +use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\HttpKernel\Profiler\Profiler; @@ -30,7 +32,7 @@ name: 'import:eventfeed', description: 'Import contest data from an event feed following the Contest API specification' )] -class ImportEventFeedCommand extends Command +class ImportEventFeedCommand { protected SymfonyStyle $style; @@ -43,55 +45,36 @@ public function __construct( protected readonly TokenStorageInterface $tokenStorage, protected readonly ?Profiler $profiler, protected readonly ExternalContestSourceService $sourceService, - ?string $name = null ) { - parent::__construct($name); - } - - protected function configure(): void - { - $this - ->setHelp( - 'Import contest data from an event feed following the Contest API specification:' . PHP_EOL . - GI::CCS_SPEC_API_URL . ' or any version starting from "2021-11"' . PHP_EOL . PHP_EOL . - 'Note the following assumptions and caveats:' . PHP_EOL . - '- Configuration data will only be verified.' . PHP_EOL . - '- Team members will not be imported.' . PHP_EOL . - '- Awards will not be imported.' . PHP_EOL . - '- State will not be imported.' - ) - ->addArgument( - 'contestid', - InputArgument::OPTIONAL, - 'The ID of the contest to use.' - ) - ->addOption( - 'from-start', - 's', - InputOption::VALUE_NONE, - 'Restart importing events from the beginning. ' . - 'If this option is not given, importing will resume where it left off.' - ) - ->addOption( - 'skip-event-id', - 'k', - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - "ID('s) of events to skip." - ); } /** + * @param list $eventsToSkip * @throws ClientExceptionInterface * @throws NonUniqueResultException * @throws RedirectionExceptionInterface * @throws ServerExceptionInterface */ - protected function execute(InputInterface $input, OutputInterface $output): int - { + public function __invoke( + InputInterface $input, + OutputInterface $output, + #[Option(description: "ID('s) of events to skip.", shortcut: 'k')] + array $eventsToSkip = [], + #[Argument(description: 'The ID of the contest to use.')] + ?string $contestId = null, + #[Option(description: 'Restart importing events from the beginning. If this option is not given, importing will resume where it left off.', shortcut: 's')] + bool $fromStart = false, + ): int { $this->style = new SymfonyStyle($input, $output); // Disable SQL logging and profiling. This would cause a serious memory leak otherwise // since this is a long-running process. - $this->em->getConnection()->getConfiguration()->setSQLLogger(); + $configuration = $this->em->getConnection()->getConfiguration(); + $middlewares = $configuration->getMiddlewares(); + $middlewares = array_filter( + $middlewares, + static fn (MiddlewareInterface $middleware): bool => !$middleware instanceof Middleware && !$middleware instanceof DebugMiddleware + ); + $this->em->getConnection()->getConfiguration()->setMiddlewares($middlewares); $this->profiler?->disable(); $output->setVerbosity(OutputInterface::VERBOSITY_NORMAL); @@ -99,7 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int pcntl_signal(SIGTERM, $this->stopCommand(...)); pcntl_signal(SIGINT, $this->stopCommand(...)); - if (!$this->loadSource($input, $output)) { + if (!$this->loadSource($input, $contestId)) { return Command::FAILURE; } @@ -126,9 +109,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $token = new UsernamePasswordToken($user, 'main', $user->getRoles()); $this->tokenStorage->setToken($token); - $fromStart = $input->getOption('from-start'); - $eventsToSkip = $input->getOption('skip-event-id'); - if (!$this->compareContestId()) { return Command::FAILURE; } @@ -140,7 +120,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $progressBar->setMessage('Start reading feed...'); $progressBar->start(); - $progressReporter = function ($readingToLastEventId) use ($progressBar) { + $progressReporter = function ($readingToLastEventId) use ($progressBar): void { if ($readingToLastEventId) { $progressBar->setMessage('Scanning file for start event ' . $this->sourceService->getLastReadEventId()); } else { @@ -166,9 +146,9 @@ public function stopCommand(): void * * @return bool False if the import should stop, true otherwise. */ - protected function loadSource(InputInterface $input, OutputInterface $output): bool + protected function loadSource(InputInterface $input, ?string $contestId = null): bool { - if (!$input->getArgument('contestid')) { + if (!$contestId) { if ($input->isInteractive()) { /** @var Contest[] $contests */ $contests = $this->em->getRepository(Contest::class)->findAll(); @@ -190,8 +170,6 @@ protected function loadSource(InputInterface $input, OutputInterface $output): b $this->style->error('No contestid provided and not running in interactive mode.'); return false; } - } else { - $contestId = $input->getArgument('contestid'); } /** @var ExternalContestSource|null $source */ diff --git a/webapp/src/Command/LoadDefaultDataCommand.php b/webapp/src/Command/LoadDefaultDataCommand.php index 1f0b8b7786..cdb42f9d20 100644 --- a/webapp/src/Command/LoadDefaultDataCommand.php +++ b/webapp/src/Command/LoadDefaultDataCommand.php @@ -2,31 +2,34 @@ namespace App\Command; +use Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand; use Exception; use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; #[AsCommand( name: 'domjudge:load-default-data', description: 'Load the data needed by all DOMjudge installations' )] -class LoadDefaultDataCommand extends Command +readonly class LoadDefaultDataCommand { + public function __construct( + #[Autowire(service: 'doctrine.fixtures_load_command')] + private LoadDataFixturesDoctrineCommand $loadDataFixturesDoctrineCommand + ) {} + /** * @throws Exception */ - protected function execute(InputInterface $input, OutputInterface $output): int + public function __invoke(OutputInterface $output): int { - $command = $this->getApplication()->find('doctrine:fixtures:load'); $arguments = [ - 'command' => 'doctrine:fixtures:load', '--group' => ['default'], '--append' => null, ]; - return $command->run(new ArrayInput($arguments), $output); + return $this->loadDataFixturesDoctrineCommand->run(new ArrayInput($arguments), $output); } } diff --git a/webapp/src/Command/LoadDevelopmentDataCommand.php b/webapp/src/Command/LoadDevelopmentDataCommand.php index b91ae28bc6..a721e43cff 100644 --- a/webapp/src/Command/LoadDevelopmentDataCommand.php +++ b/webapp/src/Command/LoadDevelopmentDataCommand.php @@ -2,43 +2,38 @@ namespace App\Command; +use Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand; use Exception; +use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; #[AsCommand( name: 'domjudge:load-development-data', description: 'Load fixture data to verify unit tests.' )] -class LoadDevelopmentDataCommand extends Command +readonly class LoadDevelopmentDataCommand { - protected function configure(): void - { - $this - ->addArgument( - 'TestFixture', - InputArgument::REQUIRED, - 'The name of the Test fixture to load' - ); - } + public function __construct( + #[Autowire(service: 'doctrine.fixtures_load_command')] + private LoadDataFixturesDoctrineCommand $loadDataFixturesDoctrineCommand + ) {} /** * @throws Exception */ - protected function execute(InputInterface $input, OutputInterface $output): int - { - $command = $this->getApplication()->find('doctrine:fixtures:load'); - $testDataName = $input->getArgument('TestFixture'); + public function __invoke( + #[Argument(description: 'The name of the Test fixture to load')] + string $testFixture, + OutputInterface $output + ): int { $arguments = [ - 'command' => 'doctrine:fixtures:load', - '--group' => [$testDataName], + '--group' => [$testFixture], '--append' => null, ]; - return $command->run(new ArrayInput($arguments), $output); + return $this->loadDataFixturesDoctrineCommand->run(new ArrayInput($arguments), $output); } } diff --git a/webapp/src/Command/LoadExampleDataCommand.php b/webapp/src/Command/LoadExampleDataCommand.php index de140c6055..50eb9a81cf 100644 --- a/webapp/src/Command/LoadExampleDataCommand.php +++ b/webapp/src/Command/LoadExampleDataCommand.php @@ -2,31 +2,34 @@ namespace App\Command; +use Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand; use Exception; use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; #[AsCommand( name: 'domjudge:load-example-data', description: 'Load example data to get a sample DOMjudge installation up and running' )] -class LoadExampleDataCommand extends Command +readonly class LoadExampleDataCommand { + public function __construct( + #[Autowire(service: 'doctrine.fixtures_load_command')] + private LoadDataFixturesDoctrineCommand $loadDataFixturesDoctrineCommand + ) {} + /** * @throws Exception */ - protected function execute(InputInterface $input, OutputInterface $output): int + public function __invoke(OutputInterface $output): int { - $command = $this->getApplication()->find('doctrine:fixtures:load'); $arguments = [ - 'command' => 'doctrine:fixtures:load', '--group' => ['example'], '--append' => null, ]; - return $command->run(new ArrayInput($arguments), $output); + return $this->loadDataFixturesDoctrineCommand->run(new ArrayInput($arguments), $output); } } diff --git a/webapp/src/Command/LoadGatlingDataCommand.php b/webapp/src/Command/LoadGatlingDataCommand.php index ef83a13d20..1311c5b3f6 100644 --- a/webapp/src/Command/LoadGatlingDataCommand.php +++ b/webapp/src/Command/LoadGatlingDataCommand.php @@ -2,31 +2,34 @@ namespace App\Command; +use Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand; use Exception; use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; #[AsCommand( name: 'domjudge:load-gatling-data', description: 'Load the gatling data(for load testing)' )] -class LoadGatlingDataCommand extends Command +readonly class LoadGatlingDataCommand { + public function __construct( + #[Autowire(service: 'doctrine.fixtures_load_command')] + private LoadDataFixturesDoctrineCommand $loadDataFixturesDoctrineCommand + ) {} + /** * @throws Exception */ - protected function execute(InputInterface $input, OutputInterface $output): int + public function __invoke(OutputInterface $output): int { - $command = $this->getApplication()->find('doctrine:fixtures:load'); $arguments = [ - 'command' => 'doctrine:fixtures:load', '--group' => ['gatling'], '--append' => null, ]; - return $command->run(new ArrayInput($arguments), $output); + return $this->loadDataFixturesDoctrineCommand->run(new ArrayInput($arguments), $output); } } diff --git a/webapp/src/Command/RefreshCacheCommand.php b/webapp/src/Command/RefreshCacheCommand.php index f93c73024e..8f66130ba3 100644 --- a/webapp/src/Command/RefreshCacheCommand.php +++ b/webapp/src/Command/RefreshCacheCommand.php @@ -7,33 +7,27 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; #[AsCommand( name: 'domjudge:refresh-cache', description: 'Refreshes the scoreboard caches for all contests' )] -class RefreshCacheCommand extends Command +readonly class RefreshCacheCommand { public function __construct( - protected readonly EntityManagerInterface $em, - protected readonly ScoreboardService $scoreboardService, + protected EntityManagerInterface $em, + protected ScoreboardService $scoreboardService, ) { - parent::__construct(); } - protected function execute(InputInterface $input, OutputInterface $output): int + public function __invoke(SymfonyStyle $style): int { - $style = new SymfonyStyle($input, $output); - $contests = $this->em->getRepository(Contest::class)->findAll(); foreach ($contests as $contest) { $this->scoreboardService->refreshCache($contest); $style->success("Refreshed cache for contest {$contest->getName()}."); } - return Command::SUCCESS; } } diff --git a/webapp/src/Command/ResetUserPasswordCommand.php b/webapp/src/Command/ResetUserPasswordCommand.php index b0cdfe38a2..1d7e942aea 100644 --- a/webapp/src/Command/ResetUserPasswordCommand.php +++ b/webapp/src/Command/ResetUserPasswordCommand.php @@ -5,11 +5,9 @@ use App\Entity\User; use App\Utils\Utils; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; @@ -17,53 +15,34 @@ name: 'domjudge:reset-user-password', description: 'Reset the password of the given user' )] -class ResetUserPasswordCommand extends Command +readonly class ResetUserPasswordCommand { public function __construct( - protected readonly EntityManagerInterface $em, - protected readonly UserPasswordHasherInterface $passwordHasher + protected EntityManagerInterface $em, + protected UserPasswordHasherInterface $passwordHasher ) { - parent::__construct(); } - protected function configure(): void - { - $this - ->addArgument( - 'username', - InputArgument::REQUIRED, - 'The username of the user to reset the password of' - ) - ->addArgument( - 'password', - InputArgument::OPTIONAL, - 'The new password; if not provided a random password is generated' - ); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $style = new SymfonyStyle($input, $output); - - $username = $input->getArgument('username'); + public function __invoke( + #[Argument(description: 'The username of the user to reset the password of')] + string $username, + #[Argument(description: 'The new password; if not provided a random password is generated')] + ?string $password, + SymfonyStyle $style + ): int { $user = $this->em ->getRepository(User::class) ->findOneBy(['username' => $username]); - if (!$user) { $style->error('Can not find user with username ' . $username); return Command::FAILURE; } - - $password = $input->getArgument('password') ?? Utils::generatePassword(); - + $password = $password ?? Utils::generatePassword(); $user->setPassword( $this->passwordHasher->hashPassword($user, $password) ); $this->em->flush(); - $style->success('New password for ' . $username . ' is ' . $password); - return Command::SUCCESS; } } diff --git a/webapp/src/Command/ScoreboardMergeCommand.php b/webapp/src/Command/ScoreboardMergeCommand.php index 254035ca7e..f7f46ef0e0 100644 --- a/webapp/src/Command/ScoreboardMergeCommand.php +++ b/webapp/src/Command/ScoreboardMergeCommand.php @@ -16,7 +16,9 @@ use App\Utils\FreezeData; use App\Utils\Scoreboard\Scoreboard; use App\Utils\Utils; +use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -43,57 +45,18 @@ name: 'scoreboard:merge', description: 'Merges scoreboards from multiple sites from API endpoints.' )] -class ScoreboardMergeCommand extends Command +readonly class ScoreboardMergeCommand { public function __construct( - protected readonly DOMJudgeService $dj, - protected readonly ConfigurationService $config, - protected readonly Environment $twig, - protected readonly HttpClientInterface $client, - protected readonly ScoreboardService $scoreboardService, - protected readonly RouterInterface $router, + protected DOMJudgeService $dj, + protected ConfigurationService $config, + protected Environment $twig, + protected HttpClientInterface $client, + protected ScoreboardService $scoreboardService, + protected RouterInterface $router, #[Autowire('%kernel.project_dir%')] - protected readonly string $projectDir, - ?string $name = null + protected string $projectDir, ) { - parent::__construct($name); - } - - protected function configure(): void - { - $this - ->setHelp( - 'Usage example: scoreboard:merge "BAPC preliminaries" ' . - 'https://judge.gehack.nl/api/v4/contests/3/ 3 ' . - 'http://ragnargrootkoerkamp.nl/upload/uva 2' . PHP_EOL . PHP_EOL . - 'This fetches teams and scoreboard data from API endpoints and prints a merged HTML scoreboard. It assumes times in minutes.' - ) - ->addOption( - 'category', - 'c', - InputOption::VALUE_REQUIRED, - 'Name of the team category to use', - 'Participant' - ) - ->addArgument( - 'output-file', - InputArgument::REQUIRED, - 'Where to store the ZIP file with the merged scoreboard' - ) - ->addArgument( - 'contest-name', - InputArgument::REQUIRED, - 'Title of the merged contest.' - ) - ->addArgument( - 'feed-url', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'Alternating URL location of the scoreboard to merge and a comma separated list of group_ids to include.' . PHP_EOL . - 'If an URL and it requires authentication, use username:password@ in the URL' . PHP_EOL . - 'URL should have the form https:///api/v4/contests// for DOMjudge or point to any ICPC Contest API compatible contest' . PHP_EOL . - 'Only the /teams, /organizations, /problems and /scoreboard endpoint are used, so manually putting files in those locations can work as well.' . PHP_EOL . - 'Alternatively, you can mount local files directly in the container: add "- /path/to/scoreboards:/scoreboards" to "docker-compose.yml" and use "/scoreboards/eindhoven" as path.' - ); } /** @@ -116,6 +79,7 @@ protected function getEndpoint( } /** + * @param list $feedUrl * @throws ClientExceptionInterface * @throws DecodingExceptionInterface * @throws RedirectionExceptionInterface @@ -125,9 +89,22 @@ protected function getEndpoint( * @throws RuntimeError * @throws SyntaxError */ - protected function execute(InputInterface $input, OutputInterface $output): int - { - $style = new SymfonyStyle($input, $output); + public function __invoke( + #[Argument(description: 'Where to store the ZIP file with the merged scoreboard')] + string $outputFile, + #[Argument(description: 'Title of the merged contest.')] + string $contestName, + #[Argument(description: 'Alternating URL location of the scoreboard to merge and a comma separated list of group_ids to include.' . PHP_EOL . + 'If an URL and it requires authentication, use username:password@ in the URL' . PHP_EOL . + 'URL should have the form https:///api/v4/contests// for DOMjudge or point to any ICPC Contest API compatible contest' . PHP_EOL . + 'Only the /teams, /organizations, /problems and /scoreboard endpoint are used, so manually putting files in those locations can work as well.' . PHP_EOL . + 'Alternatively, you can mount local files directly in the container: add "- /path/to/scoreboards:/scoreboards" to "docker-compose.yml" and use "/scoreboards/eindhoven" as path.')] + array $feedUrl, + OutputInterface $output, + SymfonyStyle $style, + #[Option(description: 'Name of the team category to use', shortcut: 'c')] + string $category = 'Participant', + ): int { $teams = []; $nextTeamId = 0; $problems = []; @@ -141,29 +118,26 @@ protected function execute(InputInterface $input, OutputInterface $output): int $affiliations = []; $firstSolve = []; $contest = (new Contest()) - ->setName($input->getArgument('contest-name')); + ->setName($contestName); $freezeData = null; $category = (new TeamCategory()) - ->setName($input->getOption('category')) + ->setName($category) ->setCategoryid(0); - /** @var string[] $siteArguments */ - $siteArguments = $input->getArgument('feed-url'); - // Convert from flat list to list of (url, groups) pairs $sites = []; - if (count($siteArguments) % 2 != 0) { + if (count($feedUrl) % 2 != 0) { $style->error("Provide an even number of arguments: all pairs of url and comma separated group ids."); return Command::FAILURE; } - for ($i = 0; $i < count($siteArguments); $i += 2) { + for ($i = 0; $i < count($feedUrl); $i += 2) { $site = []; - $site['path'] = $siteArguments[$i]; + $site['path'] = $feedUrl[$i]; # Some simple validation to make sure we're actually parsing group ids. - $groupsString = $siteArguments[$i + 1]; + $groupsString = $feedUrl[$i + 1]; $site['group_ids'] = explode(',', $groupsString); $sites[] = $site; } @@ -404,7 +378,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $zip = new ZipArchive(); - $result = $zip->open($input->getArgument('output-file'), + $result = $zip->open($outputFile, ZipArchive::CREATE | ZipArchive::OVERWRITE); if ($result !== true) { $style->error('Can not open output file to write ZIP to: ' . $result); @@ -434,8 +408,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $zip->close(); - $style->success(sprintf('Merged scoreboard data written to %s', - $input->getArgument('output-file'))); + $style->success(sprintf('Merged scoreboard data written to %s', $outputFile)); return Command::SUCCESS; } } diff --git a/webapp/src/Config/Loader/YamlConfigLoader.php b/webapp/src/Config/Loader/YamlConfigLoader.php index e7bd28c6ce..226a68a69d 100644 --- a/webapp/src/Config/Loader/YamlConfigLoader.php +++ b/webapp/src/Config/Loader/YamlConfigLoader.php @@ -12,10 +12,7 @@ */ class YamlConfigLoader extends FileLoader { - /** - * @return mixed - */ - public function load(mixed $resource, ?string $type = null) + public function load(mixed $resource, ?string $type = null): mixed { return Yaml::parse(file_get_contents($resource)); } diff --git a/webapp/src/Controller/API/AccessController.php b/webapp/src/Controller/API/AccessController.php index 08ba90b2d5..eeb142f14a 100644 --- a/webapp/src/Controller/API/AccessController.php +++ b/webapp/src/Controller/API/AccessController.php @@ -12,7 +12,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[Rest\Route('/contests/{cid}/access')] +#[Rest\Route(path: '/contests/{cid}/access')] #[OA\Tag(name: 'Access')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -31,7 +31,7 @@ class AccessController extends AbstractApiController * @return Access */ #[IsGranted('ROLE_API_READER')] - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Access information for the given contest', diff --git a/webapp/src/Controller/API/AccountController.php b/webapp/src/Controller/API/AccountController.php index 628792ecf0..15e5e4a664 100644 --- a/webapp/src/Controller/API/AccountController.php +++ b/webapp/src/Controller/API/AccountController.php @@ -17,7 +17,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/contests/{cid}')] +#[Rest\Route(path: '/contests/{cid}')] #[OA\Tag(name: 'Accounts')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -38,7 +38,7 @@ class AccountController extends AbstractRestController * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('/accounts')] + #[Rest\Get(path: '/accounts')] #[OA\Response( response: 200, description: 'Returns all the accounts for this contest', @@ -66,7 +66,7 @@ public function listAction(Request $request): Response * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('/accounts/{id}')] + #[Rest\Get(path: '/accounts/{id}')] #[OA\Response( response: 200, description: 'Returns the given account', @@ -83,7 +83,7 @@ public function singleAction(Request $request, string $id): Response /** * Get information about the currently logged in account. */ - #[Rest\Get('/account')] + #[Rest\Get(path: '/account')] #[OA\Response( response: 200, description: 'Information about the logged in account', diff --git a/webapp/src/Controller/API/AwardsController.php b/webapp/src/Controller/API/AwardsController.php index e51d3f55a3..216ec5541c 100644 --- a/webapp/src/Controller/API/AwardsController.php +++ b/webapp/src/Controller/API/AwardsController.php @@ -19,7 +19,7 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -#[Rest\Route('/contests/{cid}/awards')] +#[Rest\Route(path: '/contests/{cid}/awards')] #[OA\Tag(name: 'Awards')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -46,7 +46,7 @@ public function __construct( * * @return Award[] */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns the current teams qualifying for each award', @@ -66,7 +66,7 @@ public function listAction(Request $request): array * * @throws Exception */ - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the award for this contest', diff --git a/webapp/src/Controller/API/BalloonController.php b/webapp/src/Controller/API/BalloonController.php index 0ef708184b..c325e6304f 100644 --- a/webapp/src/Controller/API/BalloonController.php +++ b/webapp/src/Controller/API/BalloonController.php @@ -16,7 +16,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_API_READER') or is_granted('ROLE_BALLOON')"))] -#[Rest\Route('/contests/{cid}/balloons')] +#[Rest\Route(path: '/contests/{cid}/balloons')] #[OA\Tag(name: 'Balloons')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Response(ref: '#/components/responses/NotFound', response: 404)] @@ -31,7 +31,7 @@ class BalloonController extends AbstractApiController * @throws NonUniqueResultException * @return Balloon[] */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns the balloons for this contest.', @@ -84,7 +84,7 @@ public function listAction( * Mark a specific balloon as done. */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_BALLOON')"))] - #[Rest\Post('/{balloonId<\d+>}/done')] + #[Rest\Post(path: '/{balloonId<\d+>}/done')] #[OA\Response( response: 204, description: 'The balloon was now marked as done or already marked as such.' diff --git a/webapp/src/Controller/API/ClarificationController.php b/webapp/src/Controller/API/ClarificationController.php index a502b64c82..1a52ef990c 100644 --- a/webapp/src/Controller/API/ClarificationController.php +++ b/webapp/src/Controller/API/ClarificationController.php @@ -24,7 +24,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/contests/{cid}/clarifications')] +#[Rest\Route(path: '/contests/{cid}/clarifications')] #[OA\Tag(name: 'Clarifications')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -40,7 +40,7 @@ class ClarificationController extends AbstractRestController * Note that we restrict the returned clarifications in the query builder. * @throws NonUniqueResultException */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns all the clarifications for this contest', @@ -69,7 +69,7 @@ public function listAction(Request $request): Response * team user gets general clarifications plus those sent from or to the team. * @throws NonUniqueResultException */ - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the given clarification for this contest', @@ -89,8 +89,8 @@ public function singleAction(Request $request, string $id): Response new Expression("is_granted('ROLE_TEAM') or is_granted('ROLE_API_WRITER')"), message: 'You need to have the Team Member role to add a clarification' )] - #[Rest\Post('')] - #[Rest\Put('/{id}')] + #[Rest\Post(path: '')] + #[Rest\Put(path: '/{id}')] #[OA\RequestBody( required: true, content: [ diff --git a/webapp/src/Controller/API/ContestController.php b/webapp/src/Controller/API/ContestController.php index 2dd5e8bc35..639ff05416 100644 --- a/webapp/src/Controller/API/ContestController.php +++ b/webapp/src/Controller/API/ContestController.php @@ -50,7 +50,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/contests')] +#[Rest\Route(path: '/contests')] #[OA\Tag(name: 'Contests')] #[OA\Parameter(ref: '#/components/parameters/strict')] #[OA\Response(ref: '#/components/responses/InvalidResponse', response: 400)] @@ -76,7 +76,7 @@ public function __construct( * @throws BadRequestHttpException */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('')] + #[Rest\Post(path: '')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -126,7 +126,7 @@ public function addContestAction(Request $request): string * Get all the contests. * @throws NonUniqueResultException */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns all contests visible to the user (all contests for privileged users, active contests otherwise)', @@ -151,7 +151,7 @@ public function listAction(Request $request): Response * Get the given contest. * @throws NonUniqueResultException */ - #[Rest\Get('/{cid}')] + #[Rest\Get(path: '/{cid}')] #[OA\Response( response: 200, description: 'Returns the given contest', @@ -166,7 +166,7 @@ public function singleAction(Request $request, string $cid): Response /** * Get the banner for the given contest. */ - #[Rest\Get('/{cid}/banner', name: 'contest_banner')] + #[Rest\Get(path: '/{cid}/banner', name: 'contest_banner')] #[OA\Response( response: 200, description: 'Returns the given contest banner in PNG, JPG or SVG format', @@ -202,7 +202,7 @@ public function bannerAction(Request $request, string $cid): Response * Delete the banner for the given contest. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Delete('/{cid}/banner', name: 'delete_contest_banner')] + #[Rest\Delete(path: '/{cid}/banner', name: 'delete_contest_banner')] #[OA\Response(response: 204, description: 'Deleting banner succeeded')] #[OA\Parameter(ref: '#/components/parameters/cid')] public function deleteBannerAction(Request $request, string $cid): Response @@ -270,7 +270,7 @@ public function setBannerAction(Request $request, string $cid, ValidatorInterfac * Delete the problemset document for the given contest. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Delete('/{cid}/problemset', name: 'delete_contest_problemset')] + #[Rest\Delete(path: '/{cid}/problemset', name: 'delete_contest_problemset')] #[OA\Response(response: 204, description: 'Deleting problemset document succeeded')] #[OA\Parameter(ref: '#/components/parameters/cid')] public function deleteProblemsetAction(Request $request, string $cid): Response @@ -342,7 +342,7 @@ public function setProblemsetAction(Request $request, string $cid, ValidatorInte /** * Get the problemset document for the given contest. */ - #[Rest\Get('/{cid}/problemset', name: 'contest_problemset')] + #[Rest\Get(path: '/{cid}/problemset', name: 'contest_problemset')] #[OA\Response( response: 200, description: 'Returns the given contest problemset document in PDF, HTML or TXT format', @@ -386,7 +386,7 @@ public function problemsetAction(Request $request, string $cid): Response * @throws NonUniqueResultException */ #[IsGranted('ROLE_API_WRITER')] - #[Rest\Patch('/{cid}')] + #[Rest\Patch(path: '/{cid}')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -498,7 +498,7 @@ public function changeStartTimeAction( * Get the contest in YAML format. * @throws NonUniqueResultException */ - #[Rest\Get('/{cid}/contest-yaml')] + #[Rest\Get(path: '/{cid}/contest-yaml')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Response( response: 200, @@ -509,7 +509,7 @@ public function getContestYamlAction(Request $request, string $cid): StreamedRes { $contest = $this->getContestWithId($request, $cid); $response = new StreamedResponse(); - $response->setCallback(function () use ($contest) { + $response->setCallback(function () use ($contest): void { echo Yaml::dump($this->importExportService->getContestYamlData($contest, false), 3); }); $response->headers->set('Content-Type', 'application/x-yaml'); @@ -525,7 +525,7 @@ public function getContestYamlAction(Request $request, string $cid): StreamedRes * Get the current contest state * @throws NonUniqueResultException */ - #[Rest\Get('/{cid}/state')] + #[Rest\Get(path: '/{cid}/state')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Response( response: 200, @@ -548,7 +548,7 @@ public function getContestStateAction(Request $request, string $cid): ContestSta * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('/{cid}/event-feed')] + #[Rest\Get(path: '/{cid}/event-feed')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter( name: 'since_id', @@ -653,7 +653,7 @@ public function getEventFeedAction( $response = new StreamedResponse(); $response->headers->set('X-Accel-Buffering', 'no'); $response->headers->set('Content-Type', 'application/x-ndjson'); - $response->setCallback(function () use ($format, $cid, $contest, $request, $since_id, $types, $strict, $stream, $metadataFactory, $kernel) { + $response->setCallback(function () use ($format, $cid, $contest, $request, $since_id, $types, $strict, $stream, $metadataFactory, $kernel): void { $lastUpdate = 0; $lastIdSent = max(0, $since_id); $lastIdExists = $since_id !== -1; // Don't try to look for event_id=0 @@ -914,7 +914,7 @@ public function getEventFeedAction( * @throws NonUniqueResultException */ #[IsGranted('ROLE_API_READER')] - #[Rest\Get('/{cid}/status')] + #[Rest\Get(path: '/{cid}/status')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Response( response: 200, @@ -926,7 +926,7 @@ public function getStatusAction(Request $request, string $cid): ContestStatus return $this->dj->getContestStats($this->getContestWithId($request, $cid)); } - #[Rest\Get('/{cid}/samples.zip', name: 'samples_data_zip')] + #[Rest\Get(path: '/{cid}/samples.zip', name: 'samples_data_zip')] #[OA\Response( response: 200, description: 'The problem samples, statement & attachments as a ZIP archive', diff --git a/webapp/src/Controller/API/ExecutableController.php b/webapp/src/Controller/API/ExecutableController.php index b035720d9a..e7bf1ceaf9 100644 --- a/webapp/src/Controller/API/ExecutableController.php +++ b/webapp/src/Controller/API/ExecutableController.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[Rest\Route('/executables')] +#[Rest\Route(path: '/executables')] #[OA\Tag(name: 'Executables')] class ExecutableController extends AbstractFOSRestController { @@ -26,7 +26,7 @@ public function __construct(protected readonly EntityManagerInterface $em, prote * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Parameter(ref: '#/components/parameters/id')] #[OA\Response( response: 200, diff --git a/webapp/src/Controller/API/GeneralInfoController.php b/webapp/src/Controller/API/GeneralInfoController.php index f792ece94c..586647c6ef 100644 --- a/webapp/src/Controller/API/GeneralInfoController.php +++ b/webapp/src/Controller/API/GeneralInfoController.php @@ -59,7 +59,7 @@ public function __construct( /** * Get the current API version */ - #[Rest\Get('/version')] + #[Rest\Get(path: '/version')] #[OA\Response( response: 200, description: 'The current API version information', @@ -73,8 +73,8 @@ public function getVersionAction(): ApiVersion /** * Get information about the API and DOMjudge */ - #[Rest\Get('/info')] - #[Rest\Get('', name: 'api_root')] + #[Rest\Get(path: '/info')] + #[Rest\Get(path: '', name: 'api_root')] #[OA\Response( response: 200, description: 'Information about the API and DOMjudge', @@ -115,7 +115,7 @@ public function getInfoAction( * @return ExtendedContestStatus[] */ #[IsGranted('ROLE_API_READER')] - #[Rest\Get('/status')] + #[Rest\Get(path: '/status')] #[OA\Response( response: 200, description: 'General status information for the currently active contests', @@ -147,7 +147,7 @@ public function getStatusAction(): array * Get information about the currently logged in user. */ #[IsGranted('IS_AUTHENTICATED_FULLY')] - #[Rest\Get('/user')] + #[Rest\Get(path: '/user')] #[OA\Response( response: 200, description: 'Information about the logged in user', @@ -163,7 +163,7 @@ public function getUserAction(): User * * @return array> */ - #[Rest\Get('/config')] + #[Rest\Get(path: '/config')] #[OA\Response( response: 200, description: 'The configuration variables', @@ -206,7 +206,7 @@ public function getDatabaseConfigurationAction( * @throws NonUniqueResultException */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Put('/config')] + #[Rest\Put(path: '/config')] #[OA\Response( response: 200, description: 'The full configuration after change', @@ -244,7 +244,7 @@ public function updateConfigurationAction(Request $request): JsonResponse|array * Check the DOMjudge configuration. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Get('/config/check')] + #[Rest\Get(path: '/config/check')] #[OA\Response( response: 200, description: 'Result of the various checks performed, no problems found', @@ -288,7 +288,7 @@ public function getConfigCheckAction(SerializerInterface $serializer): Response /** * Get the flag for the given country. */ - #[Rest\Get('/country-flags/{countryCode}/{size}')] + #[Rest\Get(path: '/country-flags/{countryCode}/{size}')] #[OA\Response( response: 200, description: 'Returns the given country flag in SVG format', @@ -333,7 +333,7 @@ public function countryFlagAction( * @return array{problem_id: string, messages: array} */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('/problems')] + #[Rest\Post(path: '/problems')] #[OA\Tag(name: 'Problems')] #[OA\RequestBody( required: true, diff --git a/webapp/src/Controller/API/GroupController.php b/webapp/src/Controller/API/GroupController.php index 9adf16312d..2069cacdfd 100644 --- a/webapp/src/Controller/API/GroupController.php +++ b/webapp/src/Controller/API/GroupController.php @@ -20,7 +20,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/contests/{cid}/groups')] +#[Rest\Route(path: '/contests/{cid}/groups')] #[OA\Tag(name: 'Groups')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -34,7 +34,7 @@ class GroupController extends AbstractRestController * Get all the groups for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Parameter(ref: '#/components/parameters/idlist')] #[OA\Parameter( name: 'public', @@ -60,7 +60,7 @@ public function listAction(Request $request): Response * Get the given group for this contest * @throws NonUniqueResultException */ - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the given group for this contest', @@ -122,7 +122,7 @@ public function addAction( * Update an existing group or create one with the given ID */ #[IsGranted('ROLE_API_WRITER')] - #[Rest\Put('/{id}')] + #[Rest\Put(path: '/{id}')] #[OA\RequestBody( required: true, content: [ diff --git a/webapp/src/Controller/API/JudgehostController.php b/webapp/src/Controller/API/JudgehostController.php index e9b184606f..cfa62b3ce0 100644 --- a/webapp/src/Controller/API/JudgehostController.php +++ b/webapp/src/Controller/API/JudgehostController.php @@ -33,7 +33,6 @@ use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception as DBALException; use Doctrine\ORM\AbstractQuery; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Exception\ORMException; use Doctrine\ORM\NonUniqueResultException; @@ -53,7 +52,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[Rest\Route('/judgehosts')] +#[Rest\Route(path: '/judgehosts')] #[OA\Tag(name: 'Judgehosts')] #[OA\Response(ref: '#/components/responses/InvalidResponse', response: 400)] #[OA\Response(ref: '#/components/responses/Unauthenticated', response: 401)] @@ -78,7 +77,7 @@ public function __construct( * @return Judgehost[] */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'The judgehosts', @@ -118,7 +117,7 @@ public function getJudgehostsAction( * @throws NonUniqueResultException */ #[IsGranted('ROLE_JUDGEHOST')] - #[Rest\Post('')] + #[Rest\Post(path: '')] #[OA\Response( response: 200, description: 'The returned unfinished judgings', @@ -198,7 +197,7 @@ public function createJudgehostAction(Request $request): array * @return Judgehost[] */ #[IsGranted('ROLE_JUDGEHOST')] - #[Rest\Put('/{hostname}')] + #[Rest\Put(path: '/{hostname}')] #[OA\Response( response: 200, description: 'The modified judgehost', @@ -244,7 +243,7 @@ public function updateJudgeHostAction( * @throws NonUniqueResultException */ #[IsGranted('ROLE_JUDGEHOST')] - #[Rest\Put('/update-judging/{hostname}/{judgetaskid<\d+>}')] + #[Rest\Put(path: '/update-judging/{hostname}/{judgetaskid<\d+>}')] #[OA\Response( response: 200, description: 'When the judging has been updated' @@ -316,7 +315,7 @@ public function updateJudgingAction( // Note: we use ->get here instead of ->has since entry_point can be the empty string and then we do not // want to update the submission or send out an update event if ($request->request->get('entry_point')) { - $this->em->wrapInTransaction(function () use ($query, $request, &$judging) { + $this->em->wrapInTransaction(function () use ($query, $request, &$judging): void { $submission = $judging->getSubmission(); if ($submission->getEntryPoint() === $request->request->get('entry_point')) { return; @@ -390,7 +389,7 @@ public function updateJudgingAction( $query, $output_compile, $compileMetadata - ) { + ): void { if ($judging->getOutputCompile() === null) { $judging ->setOutputCompile($output_compile) @@ -476,7 +475,7 @@ public function updateJudgingAction( * Add back debug info. */ #[IsGranted('ROLE_JUDGEHOST')] - #[Rest\Post('/add-debug-info/{hostname}/{judgeTaskId<\d+>}')] + #[Rest\Post(path: '/add-debug-info/{hostname}/{judgeTaskId<\d+>}')] #[OA\Response(response: 200, description: 'When the debug info has been added')] public function addDebugInfo( Request $request, @@ -561,7 +560,7 @@ public function addDebugInfo( * @throws ORMException */ #[IsGranted('ROLE_JUDGEHOST')] - #[Rest\Post('/add-judging-run/{hostname}/{judgeTaskId<\d+>}')] + #[Rest\Post(path: '/add-judging-run/{hostname}/{judgeTaskId<\d+>}')] #[OA\Response(response: 200, description: 'When the judging run has been added')] #[OA\RequestBody( required: true, @@ -677,7 +676,7 @@ public function addJudgingRunAction( * @throws ORMException */ #[IsGranted('ROLE_JUDGEHOST')] - #[Rest\Post('/internal-error')] + #[Rest\Post(path: '/internal-error')] #[OA\Response( response: 200, description: 'The ID of the created internal error', @@ -811,7 +810,7 @@ public function internalErrorAction(Request $request): ?int if ($field_name !== null) { // Disable any outstanding judgetasks with the same script that have not been claimed yet. - $this->em->wrapInTransaction(function (EntityManager $em) use ($field_name, $disabled_id, $error) { + $this->em->wrapInTransaction(function (EntityManagerInterface $em) use ($field_name, $disabled_id, $error): void { $judgingids = $em->getConnection()->executeQuery( 'SELECT DISTINCT jobid' . ' FROM judgetask' @@ -865,7 +864,7 @@ protected function giveBackJudging(int $judgingId, ?Judgehost $judgehost): void { $judging = $this->em->getRepository(Judging::class)->find($judgingId); if ($judging) { - $this->em->wrapInTransaction(function () use ($judging, $judgehost) { + $this->em->wrapInTransaction(function () use ($judging, $judgehost): void { /** @var JudgingRun $run */ foreach ($judging->getRuns() as $run) { if ($judgehost === null) { @@ -960,7 +959,7 @@ private function addSingleJudgingRun( $metadata, $testcasedir, $compareMeta - ) { + ): void { $judgingRun = $this->em->getRepository(JudgingRun::class)->findOneBy( ['judgetaskid' => $judgeTaskId]); if ($judgingRun === null) { @@ -1223,7 +1222,7 @@ private function maybeUpdateActiveJudging(Judging $judging): void * @return JudgehostFile[] */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Get('/get_files/{type}/{id<\d+>}')] + #[Rest\Get(path: '/get_files/{type}/{id<\d+>}')] #[OA\Response( response: 200, description: 'The files for the submission, testcase or script.', @@ -1249,7 +1248,7 @@ public function getFilesAction( * @return array{compiler_version_command?: string, runner_version_command?: string} */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Get('/get_version_commands/{judgetaskid<\d+>}')] + #[Rest\Get(path: '/get_version_commands/{judgetaskid<\d+>}')] #[OA\Response( response: 200, description: 'Returns optionally compiler and runner version commands.', @@ -1291,7 +1290,7 @@ public function getVersionCommands(string $judgetaskid): array * @return array{} */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Put('/check_versions/{judgetaskid}')] + #[Rest\Put(path: '/check_versions/{judgetaskid}')] #[OA\Response( response: 200, description: 'Updates internal versions, does not check them yet.', @@ -1360,7 +1359,7 @@ public function checkVersions(Request $request, string $judgetaskid): array $reportedVersions, $language, $judgeTask - ) { + ): void { $activeVersion = $this->em->getRepository(Version::class) ->findOneBy(['language' => $language, 'judgehost' => $judgehost, 'active' => true]); @@ -1503,7 +1502,7 @@ private function getTestcaseFiles(string $id): array * @return JudgeTask[] */ #[IsGranted(new Expression("is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Post('/fetch-work')] + #[Rest\Post(path: '/fetch-work')] #[OA\Response( response: 200, description: 'Returns the workarray.', @@ -1773,7 +1772,7 @@ private function serializeJudgeTasks(array $judgeTasks, Judgehost $judgehost): a ); } - if ($numUpdated == sizeof($judgeTasks)) { + if ($numUpdated == count($judgeTasks)) { // We got everything, let's ship it! return $judgeTasks; } diff --git a/webapp/src/Controller/API/JudgementController.php b/webapp/src/Controller/API/JudgementController.php index 94941a1bca..0db1862f89 100644 --- a/webapp/src/Controller/API/JudgementController.php +++ b/webapp/src/Controller/API/JudgementController.php @@ -21,7 +21,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/')] +#[Rest\Route(path: '/')] #[OA\Tag(name: 'Judgements')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -52,8 +52,8 @@ public function __construct( * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_TEAM') or is_granted('ROLE_JUDGEHOST') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('contests/{cid}/judgements')] - #[Rest\Get('judgements')] + #[Rest\Get(path: 'contests/{cid}/judgements')] + #[Rest\Get(path: 'judgements')] #[OA\Response( response: 200, description: 'Returns all the judgements for this contest', @@ -85,8 +85,8 @@ public function listAction(Request $request): Response * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_TEAM') or is_granted('ROLE_JUDGEHOST') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('contests/{cid}/judgements/{id<\d+>}')] - #[Rest\Get('judgements/{id<\d+>}')] + #[Rest\Get(path: 'contests/{cid}/judgements/{id<\d+>}')] + #[Rest\Get(path: 'judgements/{id<\d+>}')] #[OA\Response( response: 200, description: 'Returns the given judgement for this contest', diff --git a/webapp/src/Controller/API/JudgementTypeController.php b/webapp/src/Controller/API/JudgementTypeController.php index 0840ae3662..aee96ca3dc 100644 --- a/webapp/src/Controller/API/JudgementTypeController.php +++ b/webapp/src/Controller/API/JudgementTypeController.php @@ -10,7 +10,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -#[Rest\Route('/contests/{cid}/judgement-types')] +#[Rest\Route(path: '/contests/{cid}/judgement-types')] #[OA\Tag(name: 'Judgement types')] #[OA\Parameter(ref: '#/components/parameters/strict')] #[OA\Response(ref: '#/components/responses/InvalidResponse', response: 400)] @@ -23,7 +23,7 @@ class JudgementTypeController extends AbstractApiController * @throws NonUniqueResultException * @return JudgementType[] */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns all the judgement types for this contest', @@ -56,7 +56,7 @@ public function listAction(Request $request): array * Get the given judgement type for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the given judgement type for this contest', diff --git a/webapp/src/Controller/API/LanguageController.php b/webapp/src/Controller/API/LanguageController.php index 7073e7bace..1d9f0cbdab 100644 --- a/webapp/src/Controller/API/LanguageController.php +++ b/webapp/src/Controller/API/LanguageController.php @@ -21,7 +21,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/')] +#[Rest\Route(path: '/')] #[OA\Tag(name: 'Languages')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -34,9 +34,9 @@ class LanguageController extends AbstractRestController * Get all the languages for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('languages')] + #[Rest\Get(path: 'languages')] // The languages endpoint doesn't require `cid` but the CLICS spec requires us to also expose it under a contest. - #[Rest\Get('contests/{cid}/languages')] + #[Rest\Get(path: 'contests/{cid}/languages')] #[OA\Response( response: 200, description: 'Returns all the languages for this contest', @@ -55,9 +55,9 @@ public function listAction(Request $request): Response * Get the given language for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('languages/{id}')] + #[Rest\Get(path: 'languages/{id}')] // The languages endpoint doesn't require `cid` but the CLICS spec requires us to also expose it under a contest. - #[Rest\Get('contests/{cid}/languages/{id}')] + #[Rest\Get(path: 'contests/{cid}/languages/{id}')] #[OA\Response( response: 200, description: 'Returns the given language for this contest', @@ -74,7 +74,7 @@ public function singleAction(Request $request, string $id): Response * @throws NonUniqueResultException */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('languages/{id}/executable')] + #[Rest\Post(path: 'languages/{id}/executable')] #[OA\Response( response: 200, description: 'Update the executable for a given language.', @@ -128,7 +128,7 @@ public function updateExecutableActions(Request $request, string $id): void } #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('languages')] + #[Rest\Post(path: 'languages')] #[OA\Response( response: 200, description: 'Configure all specified languages.', diff --git a/webapp/src/Controller/API/MetricsController.php b/webapp/src/Controller/API/MetricsController.php index 0b9e53da0d..203d9f3bf3 100644 --- a/webapp/src/Controller/API/MetricsController.php +++ b/webapp/src/Controller/API/MetricsController.php @@ -38,7 +38,7 @@ public function __construct( /** * Metrics of this installation for use by Prometheus. */ - #[Rest\Get('/prometheus')] + #[Rest\Get(path: '/prometheus')] #[OA\Response( response: 200, description: 'Metrics of this installation for use by Prometheus', @@ -165,11 +165,11 @@ public function prometheusAction(): Response reset($teamsusers); // Total number of teams in the contest. - $total_teams = sizeof($teams); + $total_teams = count($teams); $m['teams']->set($total_teams, $labels); // Total number of users in teams in the contest. - $total_teams_users = sizeof($teamsusers); + $total_teams_users = count($teamsusers); $m['teams_users']->set($total_teams_users, $labels); // Figure out how many of the teams have users that logged in. @@ -234,7 +234,7 @@ public function prometheusAction(): Response ->setParameter('cid', $contest->getCid()) ->getQuery() ->getResult(); - $m['balloons_waiting']->set(sizeof($balloons_waiting), $labels); + $m['balloons_waiting']->set(count($balloons_waiting), $labels); $balloons_longest_waitingtime = 0.0; $n = Utils::now(); @@ -250,7 +250,7 @@ public function prometheusAction(): Response ->from(QueueTask::class, 'qt') ->getQuery()->getResult(); - $m['queuetasks']->set(sizeof($queueTasks)); + $m['queuetasks']->set(count($queueTasks)); // Kinda ugly that we have to go to the registry directly to get the metrics out for // rendering, but it seems to work well enough. diff --git a/webapp/src/Controller/API/OrganizationController.php b/webapp/src/Controller/API/OrganizationController.php index 52f02aab1f..1adcfc01d8 100644 --- a/webapp/src/Controller/API/OrganizationController.php +++ b/webapp/src/Controller/API/OrganizationController.php @@ -28,7 +28,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/')] +#[Rest\Route(path: '/')] #[OA\Tag(name: 'Organizations')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -52,8 +52,8 @@ public function __construct( * Get all the organizations for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('contests/{cid}/organizations')] - #[Rest\Get('organizations')] + #[Rest\Get(path: 'contests/{cid}/organizations')] + #[Rest\Get(path: 'organizations')] #[OA\Response( response: 200, description: 'Returns all the organizations for this contest', @@ -78,8 +78,8 @@ public function listAction(Request $request): Response * Get the given organization for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('contests/{cid}/organizations/{id}')] - #[Rest\Get('organizations/{id}')] + #[Rest\Get(path: 'contests/{cid}/organizations/{id}')] + #[Rest\Get(path: 'organizations/{id}')] #[OA\Response( response: 200, description: 'Returns the given organization for this contest', @@ -94,8 +94,8 @@ public function singleAction(Request $request, string $id): Response /** * Get the logo for the given organization. */ - #[Rest\Get('contests/{cid}/organizations/{id}/logo', name: 'organization_logo')] - #[Rest\Get('organizations/{id}/logo', name: 'no_contest_organization_logo')] + #[Rest\Get(path: 'contests/{cid}/organizations/{id}/logo', name: 'organization_logo')] + #[Rest\Get(path: 'organizations/{id}/logo', name: 'no_contest_organization_logo')] #[OA\Response( response: 200, description: 'Returns the given organization logo in PNG, JPG or SVG format', @@ -132,8 +132,8 @@ public function logoAction(Request $request, string $id): Response * Delete the logo for the given organization. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Delete('contests/{cid}/organizations/{id}/logo', name: 'delete_organization_logo')] - #[Rest\Delete('organizations/{id}/logo')] + #[Rest\Delete(path: 'contests/{cid}/organizations/{id}/logo', name: 'delete_organization_logo')] + #[Rest\Delete(path: 'organizations/{id}/logo')] #[OA\Response(response: 204, description: 'Deleting logo succeeded')] #[OA\Parameter(ref: '#/components/parameters/id')] public function deleteLogoAction(Request $request, string $id): Response @@ -166,10 +166,10 @@ public function deleteLogoAction(Request $request, string $id): Response * Set the logo for the given organization. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('contests/{cid}/organizations/{id}/logo', name: 'post_organization_logo')] - #[Rest\Post('organizations/{id}/logo')] - #[Rest\Put('contests/{cid}/organizations/{id}/logo', name: 'put_organization_logo')] - #[Rest\Put('organizations/{id}/logo')] + #[Rest\Post(path: 'contests/{cid}/organizations/{id}/logo', name: 'post_organization_logo')] + #[Rest\Post(path: 'organizations/{id}/logo')] + #[Rest\Put(path: 'contests/{cid}/organizations/{id}/logo', name: 'put_organization_logo')] + #[Rest\Put(path: 'organizations/{id}/logo')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -230,8 +230,8 @@ public function setLogoAction(Request $request, string $id, ValidatorInterface $ * Add a new organization. */ #[IsGranted('ROLE_API_WRITER')] - #[Rest\Post('contests/{cid}/organizations')] - #[Rest\Post('organizations')] + #[Rest\Post(path: 'contests/{cid}/organizations')] + #[Rest\Post(path: 'organizations')] #[OA\RequestBody( required: true, content: [ diff --git a/webapp/src/Controller/API/ProblemController.php b/webapp/src/Controller/API/ProblemController.php index 479c96b105..8f559dfb83 100644 --- a/webapp/src/Controller/API/ProblemController.php +++ b/webapp/src/Controller/API/ProblemController.php @@ -35,7 +35,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/contests/{cid}/problems')] +#[Rest\Route(path: '/contests/{cid}/problems')] #[OA\Tag(name: 'Problems')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -64,7 +64,7 @@ public function __construct( * @throws NonUniqueResultException */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('/add-data')] + #[Rest\Post(path: '/add-data')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -119,7 +119,7 @@ public function addProblemsAction(Request $request): array * Get all the problems for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns all the problems for this contest', @@ -180,7 +180,7 @@ public function listAction(Request $request): Response * @throws NonUniqueResultException */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('')] + #[Rest\Post(path: '')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -241,7 +241,7 @@ public function addProblemAction(Request $request): array * Unlink a problem from this contest. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Delete('/{id}')] + #[Rest\Delete(path: '/{id}')] #[OA\Response(response: 204, description: 'Problem unlinked from contest succeeded')] #[OA\Parameter(ref: '#/components/parameters/id')] public function unlinkProblemAction(Request $request, string $id): Response @@ -294,7 +294,7 @@ public function unlinkProblemAction(Request $request, string $id): Response * Link an existing problem to this contest. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Put('/{id}')] + #[Rest\Put(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the linked problem for this contest', @@ -367,7 +367,7 @@ public function linkProblemAction( * Get the given problem for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the given problem for this contest', @@ -402,7 +402,7 @@ public function singleAction(Request $request, string $id): Response * Get the statement for given problem for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('/{id}/statement')] + #[Rest\Get(path: '/{id}/statement')] #[OA\Response( response: 200, description: 'Returns the given problem statement for this contest', @@ -441,7 +441,7 @@ public function statementAction(Request $request, string $id): Response * Get an attachment for given problem for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('/{id}/attachment/{filename}')] + #[Rest\Get(path: '/{id}/attachment/{filename}')] #[OA\Response( response: 200, description: 'Returns the given problem attachment for this contest' diff --git a/webapp/src/Controller/API/RunController.php b/webapp/src/Controller/API/RunController.php index 5a750ca5dd..caaa1a1fd8 100644 --- a/webapp/src/Controller/API/RunController.php +++ b/webapp/src/Controller/API/RunController.php @@ -22,7 +22,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/contests/{cid}/runs')] +#[Rest\Route(path: '/contests/{cid}/runs')] #[OA\Tag(name: 'Runs')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -54,7 +54,7 @@ public function __construct( * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns all the runs for this contest', @@ -98,7 +98,7 @@ public function listAction(Request $request): Response * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('/{id<\d+>}')] + #[Rest\Get(path: '/{id<\d+>}')] #[OA\Response( response: 200, description: 'Returns the given run for this contest', diff --git a/webapp/src/Controller/API/ScoreboardController.php b/webapp/src/Controller/API/ScoreboardController.php index 51f0c23a3c..43702091cf 100644 --- a/webapp/src/Controller/API/ScoreboardController.php +++ b/webapp/src/Controller/API/ScoreboardController.php @@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -#[Rest\Route('/contests/{cid}/scoreboard')] +#[Rest\Route(path: '/contests/{cid}/scoreboard')] #[OA\Tag(name: 'Scoreboard')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -48,7 +48,7 @@ public function __construct( * Get the scoreboard for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns the scoreboard', diff --git a/webapp/src/Controller/API/SubmissionController.php b/webapp/src/Controller/API/SubmissionController.php index 569ab8697e..61e04adf5b 100644 --- a/webapp/src/Controller/API/SubmissionController.php +++ b/webapp/src/Controller/API/SubmissionController.php @@ -37,7 +37,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/')] +#[Rest\Route(path: '/')] #[OA\Tag(name: 'Submissions')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -61,8 +61,8 @@ public function __construct( * Get all the submissions for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('submissions')] - #[Rest\Get('contests/{cid}/submissions')] + #[Rest\Get(path: 'submissions')] + #[Rest\Get(path: 'contests/{cid}/submissions')] #[OA\Response( response: 200, description: 'Returns all the submissions for this contest', @@ -87,8 +87,8 @@ public function listAction(Request $request): Response * Get the given submission for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('submissions/{id}')] - #[Rest\Get('contests/{cid}/submissions/{id}')] + #[Rest\Get(path: 'submissions/{id}')] + #[Rest\Get(path: 'contests/{cid}/submissions/{id}')] #[OA\Response( response: 200, description: 'Returns the given submission for this contest', @@ -108,8 +108,8 @@ public function singleAction(Request $request, string $id): Response new Expression("is_granted('ROLE_TEAM') or is_granted('ROLE_API_WRITER')"), message: 'You need to have the Team Member role to add a submission' )] - #[Rest\Post('contests/{cid}/submissions')] - #[Rest\Put('contests/{cid}/submissions/{id}')] + #[Rest\Post(path: 'contests/{cid}/submissions')] + #[Rest\Put(path: 'contests/{cid}/submissions/{id}')] #[OA\RequestBody( required: true, content: [ @@ -352,8 +352,8 @@ public function addSubmissionAction( * @throws NonUniqueResultException */ #[IsGranted('ROLE_API_SOURCE_READER')] - #[Rest\Get('contests/{cid}/submissions/{id}/files', name: 'submission_files')] - #[Rest\Get('submissions/{id}/files', name: 'submission_files_root')] + #[Rest\Get(path: 'contests/{cid}/submissions/{id}/files', name: 'submission_files')] + #[Rest\Get(path: 'submissions/{id}/files', name: 'submission_files_root')] #[OA\Response( response: 200, description: 'The files for the submission as a ZIP archive', @@ -388,7 +388,7 @@ public function getSubmissionFilesAction(Request $request, string $id): Response * @return SourceCode[] */ #[IsGranted(new Expression("is_granted('ROLE_JURY') or is_granted('ROLE_JUDGEHOST')"))] - #[Rest\Get('contests/{cid}/submissions/{id}/source-code')] + #[Rest\Get(path: 'contests/{cid}/submissions/{id}/source-code')] #[OA\Response( response: 200, description: 'The files for the submission', diff --git a/webapp/src/Controller/API/TeamController.php b/webapp/src/Controller/API/TeamController.php index 27788adb34..a039ed5edc 100644 --- a/webapp/src/Controller/API/TeamController.php +++ b/webapp/src/Controller/API/TeamController.php @@ -29,7 +29,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/')] +#[Rest\Route(path: '/')] #[OA\Tag(name: 'Teams')] #[OA\Parameter(ref: '#/components/parameters/cid')] #[OA\Parameter(ref: '#/components/parameters/strict')] @@ -53,8 +53,8 @@ public function __construct( * Get all the teams for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('contests/{cid}/teams')] - #[Rest\Get('teams')] + #[Rest\Get(path: 'contests/{cid}/teams')] + #[Rest\Get(path: 'teams')] #[OA\Response( response: 200, description: 'Returns all the teams for this contest', @@ -94,8 +94,8 @@ public function listAction(Request $request): Response * Get the given team for this contest. * @throws NonUniqueResultException */ - #[Rest\Get('contests/{cid}/teams/{id}')] - #[Rest\Get('teams/{id}')] + #[Rest\Get(path: 'contests/{cid}/teams/{id}')] + #[Rest\Get(path: 'teams/{id}')] #[OA\Response( response: 200, description: 'Returns the given team for this contest', @@ -113,8 +113,8 @@ public function singleAction(Request $request, string $id): Response /** * Get the photo for the given team. */ - #[Rest\Get('contests/{cid}/teams/{id}/photo', name: 'team_photo')] - #[Rest\Get('teams/{id}/photo', name: 'no_contest_team_photo')] + #[Rest\Get(path: 'contests/{cid}/teams/{id}/photo', name: 'team_photo')] + #[Rest\Get(path: 'teams/{id}/photo', name: 'no_contest_team_photo')] #[OA\Response( response: 200, description: 'Returns the given team photo in PNG, JPG or SVG format', @@ -153,8 +153,8 @@ public function photoAction(Request $request, string $id): Response * Delete the photo for the given team. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Delete('contests/{cid}/teams/{id}/photo', name: 'delete_team_photo')] - #[Rest\Delete('teams/{id}/photo')] + #[Rest\Delete(path: 'contests/{cid}/teams/{id}/photo', name: 'delete_team_photo')] + #[Rest\Delete(path: 'teams/{id}/photo')] #[OA\Response(response: 204, description: 'Deleting photo succeeded')] #[OA\Parameter(ref: '#/components/parameters/id')] public function deletePhotoAction(Request $request, string $id): Response @@ -187,10 +187,10 @@ public function deletePhotoAction(Request $request, string $id): Response * Set the photo for the given team. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('contests/{cid}/teams/{id}/photo', name: 'post_team_photo')] - #[Rest\Post('teams/{id}/photo')] - #[Rest\Put('contests/{cid}/teams/{id}/photo', name: 'put_team_photo')] - #[Rest\Put('teams/{id}/photo')] + #[Rest\Post(path: 'contests/{cid}/teams/{id}/photo', name: 'post_team_photo')] + #[Rest\Post(path: 'teams/{id}/photo')] + #[Rest\Put(path: 'contests/{cid}/teams/{id}/photo', name: 'put_team_photo')] + #[Rest\Put(path: 'teams/{id}/photo')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -251,8 +251,8 @@ public function setPhotoAction(Request $request, string $id, ValidatorInterface * Add a new team. */ #[IsGranted('ROLE_API_WRITER')] - #[Rest\Post('contests/{cid}/teams')] - #[Rest\Post('teams')] + #[Rest\Post(path: 'contests/{cid}/teams')] + #[Rest\Post(path: 'teams')] #[OA\RequestBody( required: true, content: [ diff --git a/webapp/src/Controller/API/UserController.php b/webapp/src/Controller/API/UserController.php index e3135ce267..0e9d70594c 100644 --- a/webapp/src/Controller/API/UserController.php +++ b/webapp/src/Controller/API/UserController.php @@ -28,7 +28,7 @@ /** * @extends AbstractRestController */ -#[Rest\Route('/users', defaults: ['_format' => 'json'])] +#[Rest\Route(path: '/users', defaults: ['_format' => 'json'])] #[OA\Tag(name: 'Users')] #[OA\Response(ref: '#/components/responses/InvalidResponse', response: 400)] #[OA\Response(ref: '#/components/responses/Unauthenticated', response: 401)] @@ -50,7 +50,7 @@ public function __construct( * Add one or more groups. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('/groups')] + #[Rest\Post(path: '/groups')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -98,7 +98,7 @@ public function addGroupsAction(Request $request): string * Add one or more organizations. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('/organizations')] + #[Rest\Post(path: '/organizations')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -136,7 +136,7 @@ public function addOrganizationsAction(Request $request): string * Add one or more teams. */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('/teams')] + #[Rest\Post(path: '/teams')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -185,7 +185,7 @@ public function addTeamsAction(Request $request): string * @throws BadRequestHttpException */ #[IsGranted('ROLE_ADMIN')] - #[Rest\Post('/accounts')] + #[Rest\Post(path: '/accounts')] #[OA\RequestBody( required: true, content: new OA\MediaType( @@ -249,7 +249,7 @@ public function addAccountsAction(Request $request): string * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('')] + #[Rest\Get(path: '')] #[OA\Response( response: 200, description: 'Returns all the users for this contest', @@ -275,7 +275,7 @@ public function listAction(Request $request): Response * @throws NonUniqueResultException */ #[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_API_READER')"))] - #[Rest\Get('/{id}')] + #[Rest\Get(path: '/{id}')] #[OA\Response( response: 200, description: 'Returns the given user', @@ -318,7 +318,7 @@ public function addAction( * Update an existing User or create one with the given ID */ #[IsGranted('ROLE_API_WRITER')] - #[Rest\Put('/{id}')] + #[Rest\Put(path: '/{id}')] #[OA\RequestBody( required: true, content: [ diff --git a/webapp/src/Controller/BaseController.php b/webapp/src/Controller/BaseController.php index 00b17e4424..235fa2d026 100644 --- a/webapp/src/Controller/BaseController.php +++ b/webapp/src/Controller/BaseController.php @@ -239,7 +239,7 @@ protected function commitDeleteEntity(object $entity, array $primaryKeyData): vo } // Now actually delete the entity. - $this->em->wrapInTransaction(function () use ($entity) { + $this->em->wrapInTransaction(function () use ($entity): void { if ($entity instanceof Problem) { // Deleting a problem is a special case: // Its dependent tables do not form a tree (but something like a diamond shape), @@ -610,7 +610,7 @@ protected function streamResponse(RequestStack $requestStack, callable $callback $mainRequest = $requestStack->getMainRequest(); $response = new StreamedResponse(); $response->headers->set('X-Accel-Buffering', 'no'); - $response->setCallback(function () use ($requestStack, $callback, $mainRequest) { + $response->setCallback(function () use ($requestStack, $callback, $mainRequest): void { $requestStack->push($mainRequest); $callback(); }); diff --git a/webapp/src/Controller/Jury/ContestController.php b/webapp/src/Controller/Jury/ContestController.php index b8c4c5e419..e4fd8b251e 100644 --- a/webapp/src/Controller/Jury/ContestController.php +++ b/webapp/src/Controller/Jury/ContestController.php @@ -638,7 +638,7 @@ function () use ($form, $contest) { return $response; } - $this->em->wrapInTransaction(function () use ($contest) { + $this->em->wrapInTransaction(function () use ($contest): void { // A little 'hack': we need to first persist and save the // contest, before we can persist and save the problem, // because we need a contest ID. diff --git a/webapp/src/Controller/Jury/ImportExportController.php b/webapp/src/Controller/Jury/ImportExportController.php index 6f07dfd71a..e2882e1139 100644 --- a/webapp/src/Controller/Jury/ImportExportController.php +++ b/webapp/src/Controller/Jury/ImportExportController.php @@ -198,7 +198,7 @@ public function indexAction(Request $request): Response /** @var Contest $contest */ $contest = $contestExportForm->get('contest')->getData(); $response = new StreamedResponse(); - $response->setCallback(function () use ($contest) { + $response->setCallback(function () use ($contest): void { echo Yaml::dump($this->importExportService->getContestYamlData($contest), 3); }); $response->headers->set('Content-Type', 'application/x-yaml'); @@ -299,7 +299,7 @@ public function indexAction(Request $request): Response $sortOrder, $individuallyRanked, $honors - ) { + ): void { if ($format === 'tsv') { $data = $this->importExportService->getResultsData( $sortOrder->sort_order, @@ -360,7 +360,7 @@ public function exportTsvAction(string $type): Response } $response = new StreamedResponse(); - $response->setCallback(function () use ($tsvType, $data) { + $response->setCallback(function () use ($tsvType, $data): void { $version = 1; echo sprintf("%s\t%s\n", $tsvType, $version); foreach ($data as $row) { diff --git a/webapp/src/Controller/Jury/InternalErrorController.php b/webapp/src/Controller/Jury/InternalErrorController.php index 04642dab40..fc75c1abe6 100644 --- a/webapp/src/Controller/Jury/InternalErrorController.php +++ b/webapp/src/Controller/Jury/InternalErrorController.php @@ -161,12 +161,12 @@ public function handleAction(Request $request, ?Profiler $profiler, int $errorId if ($request->isXmlHttpRequest()) { $profiler?->disable(); - $progressReporter = function (int $progress, string $log, ?string $message = null) { + $progressReporter = function (int $progress, string $log, ?string $message = null): void { echo Utils::jsonEncode(['progress' => $progress, 'log' => htmlspecialchars($log), 'message' => $message]); ob_flush(); flush(); }; - return $this->streamResponse($this->requestStack, function () use ($progressReporter, $internalError) { + return $this->streamResponse($this->requestStack, function () use ($progressReporter, $internalError): void { $internalError->setStatus(InternalErrorStatusType::STATUS_RESOLVED); $this->dj->setInternalError( $internalError->getDisabled(), diff --git a/webapp/src/Controller/Jury/JuryMiscController.php b/webapp/src/Controller/Jury/JuryMiscController.php index edc8ae379d..3c2f5baab6 100644 --- a/webapp/src/Controller/Jury/JuryMiscController.php +++ b/webapp/src/Controller/Jury/JuryMiscController.php @@ -220,12 +220,12 @@ public function refreshCacheAction(Request $request, ScoreboardService $scoreboa } if ($request->isXmlHttpRequest() && $request->isMethod('POST')) { - $progressReporter = function (int $progress, string $log, ?string $message = null) { + $progressReporter = function (int $progress, string $log, ?string $message = null): void { echo Utils::jsonEncode(['progress' => $progress, 'log' => htmlspecialchars($log), 'message' => $message]); ob_flush(); flush(); }; - return $this->streamResponse($this->requestStack, function () use ($contests, $progressReporter, $scoreboardService) { + return $this->streamResponse($this->requestStack, function () use ($contests, $progressReporter, $scoreboardService): void { $timeStart = microtime(true); foreach ($contests as $contest) { diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index e10cc3f6be..b06b863045 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -856,7 +856,7 @@ public function moveTestcaseAction(int $probId, int $rank, string $direction): R if ($current !== null && $other !== null) { // (probid, rank) is a unique key, so we must switch via a temporary rank, and use a transaction. - $this->em->wrapInTransaction(function () use ($current, $other, $numTestcases) { + $this->em->wrapInTransaction(function () use ($current, $other, $numTestcases): void { $otherRank = $other->getRank(); $currentRank = $current->getRank(); $other->setRank($numTestcases + 1); @@ -919,7 +919,7 @@ public function fetchTestcaseAction(int $probId, int $rank, string $type): Respo } $response = new StreamedResponse(); - $response->setCallback(function () use ($content) { + $response->setCallback(function () use ($content): void { echo $content; }); $response->headers->set('Content-Type', sprintf('%s; name="%s', $mimetype, $filename)); diff --git a/webapp/src/Controller/Jury/RejudgingController.php b/webapp/src/Controller/Jury/RejudgingController.php index da05c10a79..d3c81e783b 100644 --- a/webapp/src/Controller/Jury/RejudgingController.php +++ b/webapp/src/Controller/Jury/RejudgingController.php @@ -261,7 +261,7 @@ public function viewAction( /** @var Judging[] $newVerdicts */ $newVerdicts = []; - $this->em->wrapInTransaction(function () use ($rejudging, &$originalVerdicts, &$newVerdicts) { + $this->em->wrapInTransaction(function () use ($rejudging, &$originalVerdicts, &$newVerdicts): void { $expr = $this->em->getExpressionBuilder(); $originalVerdicts = $this->em->createQueryBuilder() ->from(Judging::class, 'j') @@ -298,7 +298,7 @@ public function viewAction( }); // Helper function to add verdicts. - $addVerdict = function ($unknownVerdict) use ($verdicts, &$verdictTable) { + $addVerdict = function ($unknownVerdict) use ($verdicts, &$verdictTable): void { // Add column to existing rows. foreach ($verdicts as $verdict => $abbreviation) { $verdictTable[$verdict][$unknownVerdict] = []; @@ -450,12 +450,12 @@ public function finishAction( ->getOneOrNullResult(); if ($request->isXmlHttpRequest()) { - $progressReporter = function (int $progress, string $log, ?string $message = null) { + $progressReporter = function (int $progress, string $log, ?string $message = null): void { echo Utils::jsonEncode(['progress' => $progress, 'log' => htmlspecialchars($log), 'message' => htmlspecialchars($message ?? '')]); ob_flush(); flush(); }; - return $this->streamResponse($this->requestStack, function () use ($progressReporter, $rejudging, $rejudgingService, $action) { + return $this->streamResponse($this->requestStack, function () use ($progressReporter, $rejudging, $rejudgingService, $action): void { $timeStart = microtime(true); if ($rejudgingService->finishRejudging($rejudging, $action, $progressReporter)) { $timeEnd = microtime(true); @@ -538,12 +538,12 @@ public function addAction(Request $request, FormFactoryInterface $formFactory): ]); } if ($isCreateRejudgingAjax) { - $progressReporter = function (int $progress, string $log, ?string $redirect = null) { + $progressReporter = function (int $progress, string $log, ?string $redirect = null): void { echo Utils::jsonEncode(['progress' => $progress, 'log' => htmlspecialchars($log), 'redirect' => $redirect]); ob_flush(); flush(); }; - return $this->streamResponse($this->requestStack, function () use ($request, $progressReporter) { + return $this->streamResponse($this->requestStack, function () use ($request, $progressReporter): void { $reason = $request->request->get('reason'); $data = $request->request->all(); @@ -723,13 +723,13 @@ public function createAction(Request $request): Response ]); } - $progressReporter = function (int $progress, string $log, ?string $redirect = null) { + $progressReporter = function (int $progress, string $log, ?string $redirect = null): void { echo Utils::jsonEncode(['progress' => $progress, 'log' => htmlspecialchars($log), 'redirect' => $redirect]); ob_flush(); flush(); }; - return $this->streamResponse($this->requestStack, function () use ($priority, $progressReporter, $repeat, $reason, $overshoot, $request, $autoApply, $includeAll, $id, $table, $tablemap) { + return $this->streamResponse($this->requestStack, function () use ($priority, $progressReporter, $repeat, $reason, $overshoot, $request, $autoApply, $includeAll, $id, $table, $tablemap): void { // Only rejudge submissions in active contests. $contests = $this->dj->getCurrentContests(); diff --git a/webapp/src/Controller/Jury/ShadowDifferencesController.php b/webapp/src/Controller/Jury/ShadowDifferencesController.php index 6462a4c679..3c5c56440d 100644 --- a/webapp/src/Controller/Jury/ShadowDifferencesController.php +++ b/webapp/src/Controller/Jury/ShadowDifferencesController.php @@ -108,7 +108,7 @@ public function indexAction( ->getResult(); // Helper function to add verdicts. - $addVerdict = function ($unknownVerdict) use ($verdicts, &$verdictTable) { + $addVerdict = function ($unknownVerdict) use ($verdicts, &$verdictTable): void { // Add column to existing rows. foreach ($verdicts as $verdict => $abbreviation) { $verdictTable[$verdict][$unknownVerdict] = []; diff --git a/webapp/src/Controller/Jury/SubmissionController.php b/webapp/src/Controller/Jury/SubmissionController.php index 3097765723..ab4383a327 100644 --- a/webapp/src/Controller/Jury/SubmissionController.php +++ b/webapp/src/Controller/Jury/SubmissionController.php @@ -1144,7 +1144,7 @@ public function verifyAction( Request $request, int $judgingId ): RedirectResponse { - $this->em->wrapInTransaction(function () use ($eventLogService, $request, $judgingId) { + $this->em->wrapInTransaction(function () use ($eventLogService, $request, $judgingId): void { /** @var Judging $judging */ $judging = $this->em->getRepository(Judging::class)->find($judgingId); $verified = $request->request->getBoolean('verified'); @@ -1212,7 +1212,7 @@ public function verifyShadowDifferenceAction( ): RedirectResponse { /** @var ExternalJudgement $judgement */ $judgement = $this->em->getRepository(ExternalJudgement::class)->find($extjudgementid); - $this->em->wrapInTransaction(function () use ($request, $judgement) { + $this->em->wrapInTransaction(function () use ($request, $judgement): void { $verified = $request->request->getBoolean('verified'); $comment = $request->request->get('comment'); $judgement diff --git a/webapp/src/DependencyInjection/Compiler/DoctrineNativeLazyObjectsPass.php b/webapp/src/DependencyInjection/Compiler/DoctrineNativeLazyObjectsPass.php new file mode 100644 index 0000000000..7961f12bef --- /dev/null +++ b/webapp/src/DependencyInjection/Compiler/DoctrineNativeLazyObjectsPass.php @@ -0,0 +1,31 @@ +hasDefinition($configuration)) { + continue; + } + + $definition = $container->getDefinition($configuration); + $definition->addMethodCall('enableNativeLazyObjects', [true]); + } + } +} diff --git a/webapp/src/Doctrine/DBAL/Types/InternalErrorStatusType.php b/webapp/src/Doctrine/DBAL/Types/InternalErrorStatusType.php index fd50de24b8..5906e80b19 100644 --- a/webapp/src/Doctrine/DBAL/Types/InternalErrorStatusType.php +++ b/webapp/src/Doctrine/DBAL/Types/InternalErrorStatusType.php @@ -23,18 +23,12 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform): st return sprintf("ENUM(%s)", $statuses); } - /** - * @return mixed - */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed { return $value; } - /** - * @return mixed - */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed { if (!in_array($value, self::ALL_STATUSES)) { throw new InvalidArgumentException("Invalid status"); @@ -42,13 +36,8 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value; } - public function getName(): string + public function getMappedDatabaseTypes(AbstractPlatform $platform): array { - return self::ENUM_INTERNAL_ERROR_STATUS; - } - - public function requiresSQLCommentHint(AbstractPlatform $platform): bool - { - return true; + return ['enum']; } } diff --git a/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php b/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php index b9c2575113..26782267d1 100644 --- a/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php +++ b/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php @@ -30,18 +30,12 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform): st return sprintf("ENUM(%s)", $statuses); } - /** - * @return mixed - */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed { return $value; } - /** - * @return mixed - */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed { if (!in_array($value, self::ALL_TYPES)) { throw new InvalidArgumentException("Invalid judgetask type"); @@ -49,13 +43,8 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value; } - public function getName(): string + public function getMappedDatabaseTypes(AbstractPlatform $platform): array { - return self::ENUM_JUDGE_TASK_TYPE; - } - - public function requiresSQLCommentHint(AbstractPlatform $platform): bool - { - return true; + return ['enum']; } } diff --git a/webapp/src/Doctrine/DBAL/Types/TinyIntType.php b/webapp/src/Doctrine/DBAL/Types/TinyIntType.php index 4df3c834c6..15d6f7635d 100644 --- a/webapp/src/Doctrine/DBAL/Types/TinyIntType.php +++ b/webapp/src/Doctrine/DBAL/Types/TinyIntType.php @@ -8,11 +8,6 @@ class TinyIntType extends Type { - public function getName(): string - { - return 'tinyint'; - } - public function getSQLDeclaration(array $column, AbstractPlatform $platform): string { $declaration = 'TINYINT'; @@ -33,13 +28,13 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?int return $value === null ? null : (int)$value; } - public function getBindingType(): int + public function getBindingType(): ParameterType { return ParameterType::INTEGER; } - public function requiresSQLCommentHint(AbstractPlatform $platform): bool + public function getMappedDatabaseTypes(AbstractPlatform $platform): array { - return true; + return ['tinyint']; } } diff --git a/webapp/src/Doctrine/ORM/Query/AST/Functions/RightFunction.php b/webapp/src/Doctrine/ORM/Query/AST/Functions/RightFunction.php index 033f0adbd6..cc57ae18cc 100644 --- a/webapp/src/Doctrine/ORM/Query/AST/Functions/RightFunction.php +++ b/webapp/src/Doctrine/ORM/Query/AST/Functions/RightFunction.php @@ -5,10 +5,10 @@ use Doctrine\ORM\Query\AST\ASTException; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * Right function that truncates a field from the database from the right. @@ -35,11 +35,11 @@ public function getSql(SqlWalker $sqlWalker): string */ public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->fieldExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->lengthExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/webapp/src/Doctrine/ORM/Query/AST/Functions/TruncateFunction.php b/webapp/src/Doctrine/ORM/Query/AST/Functions/TruncateFunction.php index c31a869177..62de5832bd 100644 --- a/webapp/src/Doctrine/ORM/Query/AST/Functions/TruncateFunction.php +++ b/webapp/src/Doctrine/ORM/Query/AST/Functions/TruncateFunction.php @@ -5,10 +5,10 @@ use Doctrine\ORM\Query\AST\ASTException; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * Truncate function that truncates a field from the database if too long and adds a truncation message. @@ -40,13 +40,13 @@ public function getSql(SqlWalker $sqlWalker): string */ public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->fieldExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->lengthExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->appendWhenTruncatedExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/webapp/src/Entity/Judgehost.php b/webapp/src/Entity/Judgehost.php index 7d72e19b06..c1cde5d99b 100644 --- a/webapp/src/Entity/Judgehost.php +++ b/webapp/src/Entity/Judgehost.php @@ -28,7 +28,7 @@ class Judgehost private int $judgehostid; #[ORM\Column(length: 64, options: ['comment' => 'Resolvable hostname of judgehost'])] - #[Assert\Regex('/^[A-Za-z0-9_\-.]*$/', message: 'Invalid hostname. Only characters in [A-Za-z0-9_\-.] are allowed.')] + #[Assert\Regex(pattern: '/^[A-Za-z0-9_\-.]*$/', message: 'Invalid hostname. Only characters in [A-Za-z0-9_\-.] are allowed.')] private string $hostname; #[ORM\Column(options: ['comment' => 'Should this host take on judgings?', 'default' => 1])] diff --git a/webapp/src/Entity/Language.php b/webapp/src/Entity/Language.php index ecaed5e89a..e05d8c6d87 100644 --- a/webapp/src/Entity/Language.php +++ b/webapp/src/Entity/Language.php @@ -57,10 +57,10 @@ class Language extends BaseApiEntity implements )] #[Assert\NotBlank] #[Assert\All([ - new Assert\Regex([ - 'pattern' => '/^[^.]/', - 'message' => 'The extension should not start with a dot.' - ]) + new Assert\Regex( + pattern: '/^[^.]/', + message: 'The extension should not start with a dot.' + ) ])] #[Serializer\Type('array')] private array $extensions = []; diff --git a/webapp/src/Entity/Team.php b/webapp/src/Entity/Team.php index fd9d4e4ef2..86f3562dbc 100644 --- a/webapp/src/Entity/Team.php +++ b/webapp/src/Entity/Team.php @@ -123,7 +123,7 @@ class Team extends BaseApiEntity implements #[Serializer\Exclude] private string $addUserForTeam = self::DONT_ADD_USER; - #[Assert\Regex('/^[a-z0-9@._-]+$/i', message: 'Only alphanumeric characters and _-@. are allowed')] + #[Assert\Regex(pattern: '/^[a-z0-9@._-]+$/i', message: 'Only alphanumeric characters and _-@. are allowed')] #[Serializer\Exclude] private ?string $newUsername = null; diff --git a/webapp/src/Entity/User.php b/webapp/src/Entity/User.php index e829805659..3ddf6d1ccd 100644 --- a/webapp/src/Entity/User.php +++ b/webapp/src/Entity/User.php @@ -52,7 +52,7 @@ class User extends BaseApiEntity implements #[ORM\Column(options: ['comment' => 'User login name'])] // See: https://symfony.com/doc/current/reference/constraints/Regex.html, the regex is considered valid when empty #[Assert\NotBlank] - #[Assert\Regex('/^[a-z0-9@._-]+$/i', message: 'Only alphanumeric characters and _-@. are allowed')] + #[Assert\Regex(pattern: '/^[a-z0-9@._-]+$/i', message: 'Only alphanumeric characters and _-@. are allowed')] private string $username = ''; #[ORM\Column(options: ['comment' => 'Name'])] @@ -148,6 +148,7 @@ public function getSalt(): ?string return null; } + #[\Deprecated] public function eraseCredentials(): void { $this->plainPassword = null; diff --git a/webapp/src/Form/Type/AbstractExternalIdEntityType.php b/webapp/src/Form/Type/AbstractExternalIdEntityType.php index c79a8fbb92..25fd3e976e 100644 --- a/webapp/src/Form/Type/AbstractExternalIdEntityType.php +++ b/webapp/src/Form/Type/AbstractExternalIdEntityType.php @@ -30,10 +30,8 @@ protected function addExternalIdField(FormBuilderInterface $builder, string $ent 'empty_data' => '', 'constraints' => [ new Regex( - [ - 'pattern' => DOMJudgeService::EXTERNAL_IDENTIFIER_REGEX, - 'message' => 'Only letters, numbers, dashes, underscores and dots are allowed.', - ] + pattern: DOMJudgeService::EXTERNAL_IDENTIFIER_REGEX, + message: 'Only letters, numbers, dashes, underscores and dots are allowed.', ), ] ]); diff --git a/webapp/src/Form/Type/ContestType.php b/webapp/src/Form/Type/ContestType.php index bcf1769bcc..92a6ac9ed4 100644 --- a/webapp/src/Form/Type/ContestType.php +++ b/webapp/src/Form/Type/ContestType.php @@ -220,7 +220,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('save', SubmitType::class); - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var Contest|null $contest */ $contest = $event->getData(); $form = $event->getForm(); diff --git a/webapp/src/Form/Type/LanguageType.php b/webapp/src/Form/Type/LanguageType.php index 2f0c70864f..8306c66a90 100644 --- a/webapp/src/Form/Type/LanguageType.php +++ b/webapp/src/Form/Type/LanguageType.php @@ -113,7 +113,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('save', SubmitType::class); // Remove ID field when doing an edit. - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var Language|null $language */ $language = $event->getData(); $form = $event->getForm(); diff --git a/webapp/src/Form/Type/ProblemType.php b/webapp/src/Form/Type/ProblemType.php index 21f7959c79..2b66e77e34 100644 --- a/webapp/src/Form/Type/ProblemType.php +++ b/webapp/src/Form/Type/ProblemType.php @@ -105,7 +105,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('save', SubmitType::class); // Remove clearProblemstatement field when we do not have a problem text. - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var Problem|null $problem */ $problem = $event->getData(); $form = $event->getForm(); diff --git a/webapp/src/Form/Type/RejudgingType.php b/webapp/src/Form/Type/RejudgingType.php index 5afcda07c6..ecfd35d6ed 100644 --- a/webapp/src/Form/Type/RejudgingType.php +++ b/webapp/src/Form/Type/RejudgingType.php @@ -115,10 +115,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'choices' => array_combine($verdicts, $verdicts), ]); $relativeTimeConstraints = [ - new Regex([ - 'pattern' => '/^[+-][0-9]+:[0-9]{2}(:[0-9]{2}(\.[0-9]{0,6})?)?$/', - 'message' => 'Invalid relative time format' - ]) + new Regex( + pattern: '/^[+-][0-9]+:[0-9]{2}(:[0-9]{2}(\.[0-9]{0,6})?)?$/', + message: 'Invalid relative time format' + ) ]; $builder->add('after', TextType::class, [ 'label' => 'after', @@ -143,7 +143,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'label' => 'Add', ]); - $formProblemModifier = function (FormInterface $form, $contests = []) { + $formProblemModifier = function (FormInterface $form, $contests = []): void { /** @var Contest[] $contests */ $problems = $this->em->createQueryBuilder() ->from(Problem::class, 'p') @@ -200,14 +200,14 @@ public function buildForm(FormBuilderInterface $builder, array $options): void }; $builder->addEventListener(FormEvents::PRE_SET_DATA, - function (FormEvent $event) use ($formProblemModifier) { + function (FormEvent $event) use ($formProblemModifier): void { $data = $event->getData(); $formProblemModifier($event->getForm(), $data['contests'] ?? []); } ); $builder->get('contests')->addEventListener(FormEvents::POST_SUBMIT, - function (FormEvent $event) use ($formProblemModifier) { + function (FormEvent $event) use ($formProblemModifier): void { $contests = $event->getForm()->getData(); $formProblemModifier($event->getForm()->getParent(), $contests); } diff --git a/webapp/src/Form/Type/SubmitProblemType.php b/webapp/src/Form/Type/SubmitProblemType.php index 997bb21555..d75fae330f 100644 --- a/webapp/src/Form/Type/SubmitProblemType.php +++ b/webapp/src/Form/Type/SubmitProblemType.php @@ -68,7 +68,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'The entry point for your code.', 'row_attr' => ['data-entry-point' => ''], 'constraints' => [ - new Callback(function ($value, ExecutionContextInterface $context) { + new Callback(function ($value, ExecutionContextInterface $context): void { /** @var Form $form */ $form = $context->getRoot(); /** @var Language $language */ @@ -85,7 +85,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ] ]); - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($problemConfig) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($problemConfig): void { if (isset($event->getData()['problem'])) { $problemConfig += ['row_attr' => ['class' => 'd-none']]; $event->getForm()->add('problem', EntityType::class, $problemConfig); diff --git a/webapp/src/Form/Type/TeamAffiliationType.php b/webapp/src/Form/Type/TeamAffiliationType.php index 46799a0dbd..c8146e88bf 100644 --- a/webapp/src/Form/Type/TeamAffiliationType.php +++ b/webapp/src/Form/Type/TeamAffiliationType.php @@ -44,10 +44,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'Optional ID of the organization in the ICPC CMS.', 'constraints' => [ new Regex( - [ - 'pattern' => '/^[a-zA-Z0-9_-]+$/i', - 'message' => 'Only letters, numbers, dashes and underscores are allowed.', - ] + pattern: '/^[a-zA-Z0-9_-]+$/i', + message: 'Only letters, numbers, dashes and underscores are allowed.', ) ] ]); @@ -77,7 +75,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); $builder->add('save', SubmitType::class); - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var TeamAffiliation|null $affiliation */ $affiliation = $event->getData(); $form = $event->getForm(); diff --git a/webapp/src/Form/Type/TeamCategoryType.php b/webapp/src/Form/Type/TeamCategoryType.php index 2752962253..4330f3e218 100644 --- a/webapp/src/Form/Type/TeamCategoryType.php +++ b/webapp/src/Form/Type/TeamCategoryType.php @@ -22,10 +22,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'Optional ID of the category in the ICPC CMS.', 'constraints' => [ new Regex( - [ - 'pattern' => '/^[a-zA-Z0-9_-]+$/i', - 'message' => 'Only letters, numbers, dashes and underscores are allowed.', - ] + pattern: '/^[a-zA-Z0-9_-]+$/i', + message: 'Only letters, numbers, dashes and underscores are allowed.', ) ] ]); diff --git a/webapp/src/Form/Type/TeamType.php b/webapp/src/Form/Type/TeamType.php index 5a5cdde162..40cb7549d5 100644 --- a/webapp/src/Form/Type/TeamType.php +++ b/webapp/src/Form/Type/TeamType.php @@ -48,10 +48,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'Optional ID of the team in the ICPC CMS.', 'constraints' => [ new Regex( - [ - 'pattern' => '/^[a-zA-Z0-9_-]+$/i', - 'message' => 'Only letters, numbers, dashes and underscores are allowed.', - ] + pattern: '/^[a-zA-Z0-9_-]+$/i', + message: 'Only letters, numbers, dashes and underscores are allowed.', ) ] ]); @@ -142,7 +140,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('save', SubmitType::class); // Remove ID field when doing an edit. - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var Team|null $team */ $team = $event->getData(); $form = $event->getForm(); diff --git a/webapp/src/Form/Type/UserRegistrationType.php b/webapp/src/Form/Type/UserRegistrationType.php index 79bb519bdf..7dbcbf09dc 100644 --- a/webapp/src/Form/Type/UserRegistrationType.php +++ b/webapp/src/Form/Type/UserRegistrationType.php @@ -75,7 +75,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ], 'constraints' => [ new NotBlank(), - new Callback(function ($teamName, ExecutionContext $context) { + new Callback(function ($teamName, ExecutionContext $context): void { if ($this->em->getRepository(Team::class)->findOneBy(['name' => $teamName])) { $context->buildViolation('This team name is already in use.') ->addViolation(); @@ -200,7 +200,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); // Make sure the user has the team role to make validation work - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var User $user */ $user = $event->getData(); /** @var Role $role */ @@ -217,7 +217,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void public function configureOptions(OptionsResolver $resolver): void { - $validateAffiliation = function ($data, ExecutionContext $context) { + $validateAffiliation = function ($data, ExecutionContext $context): void { if ($this->config->get('show_affiliations')) { /** @var Form $form */ $form = $context->getRoot(); diff --git a/webapp/src/Form/Type/UserType.php b/webapp/src/Form/Type/UserType.php index 12da3e28c2..6d911cc5f1 100644 --- a/webapp/src/Form/Type/UserType.php +++ b/webapp/src/Form/Type/UserType.php @@ -91,7 +91,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('save', SubmitType::class); // Remove ID field when doing an edit - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var User|null $user */ $user = $event->getData(); $form = $event->getForm(); diff --git a/webapp/src/Kernel.php b/webapp/src/Kernel.php index febc424c2a..3e0c00456e 100644 --- a/webapp/src/Kernel.php +++ b/webapp/src/Kernel.php @@ -2,6 +2,7 @@ namespace App; +use App\DependencyInjection\Compiler\DoctrineNativeLazyObjectsPass; use App\DependencyInjection\Compiler\SetDocLinksPass; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -19,5 +20,6 @@ public function getProjectDir(): string protected function build(ContainerBuilder $container): void { $container->addCompilerPass(new SetDocLinksPass()); + $container->addCompilerPass(new DoctrineNativeLazyObjectsPass()); } } diff --git a/webapp/src/Migrations/Factory/ConfigurationServiceAwareInterface.php b/webapp/src/Migrations/Factory/ConfigurationServiceAwareInterface.php new file mode 100644 index 0000000000..68f8ba27ae --- /dev/null +++ b/webapp/src/Migrations/Factory/ConfigurationServiceAwareInterface.php @@ -0,0 +1,10 @@ +configurationService = $configurationService; + } +} diff --git a/webapp/src/Migrations/Factory/MigrationFactoryDecorator.php b/webapp/src/Migrations/Factory/MigrationFactoryDecorator.php new file mode 100644 index 0000000000..2226a00c83 --- /dev/null +++ b/webapp/src/Migrations/Factory/MigrationFactoryDecorator.php @@ -0,0 +1,34 @@ +migrationFactory->createVersion($migrationClassName); + + // Load the configuration service if the migration needs it + if ($instance instanceof ConfigurationServiceAwareInterface) { + $instance->setConfigurationService($this->configurationService); + } + + return $instance; + } +} diff --git a/webapp/src/Security/UserChecker.php b/webapp/src/Security/UserChecker.php index 6b5df054a9..950338950c 100644 --- a/webapp/src/Security/UserChecker.php +++ b/webapp/src/Security/UserChecker.php @@ -3,6 +3,7 @@ namespace App\Security; use App\Entity\User as DOMJudgeUser; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\DisabledException; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\User\UserInterface; @@ -15,7 +16,7 @@ public function checkPreAuth(UserInterface $user): void // Nothing to check. } - public function checkPostAuth(UserInterface $user): void + public function checkPostAuth(UserInterface $user, ?TokenInterface $token = null): void { if (!$user instanceof DOMJudgeUser) { return; diff --git a/webapp/src/Service/AwardService.php b/webapp/src/Service/AwardService.php index 4dd15073f7..e83f1b18a5 100644 --- a/webapp/src/Service/AwardService.php +++ b/webapp/src/Service/AwardService.php @@ -6,6 +6,7 @@ use App\Entity\Contest; use App\Entity\Team; use App\Utils\Scoreboard\Scoreboard; +use Twig\Attribute\AsTwigFilter; class AwardService { @@ -139,6 +140,7 @@ public function getAward(Contest $contest, Scoreboard $scoreboard, string $reque return null; } + #[AsTwigFilter('medalType')] public function medalType(Team $team, Contest $contest, Scoreboard $scoreboard): ?string { $teamid = $team->getExternalid(); diff --git a/webapp/src/Service/CheckConfigService.php b/webapp/src/Service/CheckConfigService.php index 5f1c76f4b3..92ad7ae27b 100644 --- a/webapp/src/Service/CheckConfigService.php +++ b/webapp/src/Service/CheckConfigService.php @@ -673,7 +673,6 @@ public function checkProblemsValidate(): ConfigCheckItem foreach ($problemerrors as $probid => $errors) { $desc .= " - Problem `p$probid`:\n"; if (count($errors) > 0 || !empty($moreproblemerrors[$probid])) { - /* @phpstan-ignore-next-line */ $desc .= (string)$errors . " " . $moreproblemerrors[$probid] . "\n"; } else { @@ -731,7 +730,6 @@ public function checkLanguagesValidate(): ConfigCheckItem foreach ($languageerrors as $langid => $errors) { $desc .= " - Language `$langid`: "; if (count($errors) > 0 || !empty($morelanguageerrors[$langid])) { - /* @phpstan-ignore-next-line */ $desc .= (string)$errors . " " . $morelanguageerrors[$langid] . "\n"; } else { diff --git a/webapp/src/Service/ConfigurationService.php b/webapp/src/Service/ConfigurationService.php index cfc308382d..6499ee29bd 100644 --- a/webapp/src/Service/ConfigurationService.php +++ b/webapp/src/Service/ConfigurationService.php @@ -121,7 +121,7 @@ public function getConfigSpecification(): array // more information. $cacheFile = $this->cacheDir . '/djDbConfig.php'; $this->configCache->cache($cacheFile, - function (ConfigCacheInterface $cache) { + function (ConfigCacheInterface $cache): void { // @codeCoverageIgnoreStart $yamlDbConfigFile = $this->etcDir . '/db-config.yaml'; $fileLocator = new FileLocator($this->etcDir); diff --git a/webapp/src/Service/DOMJudgeService.php b/webapp/src/Service/DOMJudgeService.php index 994a8c407a..63b9cfb1f5 100644 --- a/webapp/src/Service/DOMJudgeService.php +++ b/webapp/src/Service/DOMJudgeService.php @@ -66,6 +66,8 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Contracts\Cache\ItemInterface; +use Twig\Attribute\AsTwigFilter; +use Twig\Attribute\AsTwigFunction; use Twig\Environment; use ZipArchive; @@ -175,7 +177,7 @@ public function getCurrentContests( public function getCurrentContestCookie(): ?string { $request = $this->requestStack->getCurrentRequest(); - if ($request === null || $request->cookies === null) { + if ($request === null) { return null; } return $request->cookies->get('domjudge_cid'); @@ -261,6 +263,9 @@ public function getUser(): ?User return $user; } + /** + * @return bool|float|int|string|InputBag|null + */ public function getCookie(string $cookieName): bool|float|int|string|InputBag|null { if (!$this->requestStack->getCurrentRequest()) { @@ -1372,6 +1377,7 @@ public function getAssetFiles(string $path): array * @param bool $fullPath If true, get the full path. If false, get the webserver relative path * @param string|null $forceExtension If set, also return the asset path if it does not exist currently and use the given extension */ + #[AsTwigFilter('assetPath')] public function assetPath(?string $name, string $type, bool $fullPath = false, ?string $forceExtension = null): ?string { $prefix = $fullPath ? ($this->getDomjudgeWebappDir() . '/public/') : ''; @@ -1399,6 +1405,7 @@ public function assetPath(?string $name, string $type, bool $fullPath = false, ? return null; } + #[AsTwigFunction('globalBannerAssetPath')] public function globalBannerAssetPath(): ?string { // This is put in a separate method (and not as a special case in assetPath) since diff --git a/webapp/src/Service/EventLogService.php b/webapp/src/Service/EventLogService.php index 06d477c682..935ef5ade7 100644 --- a/webapp/src/Service/EventLogService.php +++ b/webapp/src/Service/EventLogService.php @@ -315,7 +315,7 @@ public function log( $query = ['ids' => $ids]; } - $this->dj->withAllRoles(function () use ($query, $url, &$response) { + $this->dj->withAllRoles(function () use ($query, $url, &$response): void { $response = $this->dj->internalApiRequest($url, Request::METHOD_GET, $query); }); @@ -485,7 +485,7 @@ public function addMissingStateEvents(Contest $contest): void // Insert all awards events. $url = sprintf('/contests/%s/awards', $contest->getExternalid()); $awards = []; - $this->dj->withAllRoles(function () use ($url, &$awards) { + $this->dj->withAllRoles(function () use ($url, &$awards): void { $response = $this->dj->internalApiRequest($url); if (!empty($response)) { $awards = Utils::jsonDecode($response); @@ -629,7 +629,7 @@ public function initStaticEvents(Contest $contest): void // of the endpoint to get current data. $urlPart = $endpoint === 'contests' ? '' : ('/' . $endpoint); $url = sprintf('/contests/%s%s', $contestId, $urlPart); - $this->dj->withAllRoles(function () use ($url, &$data) { + $this->dj->withAllRoles(function () use ($url, &$data): void { $response = $this->dj->internalApiRequest($url); $data = (empty($response) ? null : Utils::jsonDecode($response)); }); diff --git a/webapp/src/Service/ExternalContestSourceService.php b/webapp/src/Service/ExternalContestSourceService.php index 2c05ec445d..4f002845a9 100644 --- a/webapp/src/Service/ExternalContestSourceService.php +++ b/webapp/src/Service/ExternalContestSourceService.php @@ -474,7 +474,7 @@ function ( $eventsToSkip, &$skipEventsUpTo, $progressReporter - ) { + ): void { $lastEventId = $this->getLastReadEventId(); $readingToLastEventId = false; $event = $this->serializer->deserialize($line, Event::class, 'json', ['api_version' => $this->getApiVersion()]); diff --git a/webapp/src/Service/ImportExportService.php b/webapp/src/Service/ImportExportService.php index b6e4c21812..cd4d725f81 100644 --- a/webapp/src/Service/ImportExportService.php +++ b/webapp/src/Service/ImportExportService.php @@ -1133,7 +1133,7 @@ public function importAccountsJson(array $data, ?string &$message = null, ?array $accountData = []; foreach ($data as $idx => $account) { foreach (['username', 'type'] as $required) { - if (!key_exists($required, $account)) { + if (!array_key_exists($required, $account)) { $message = sprintf("Missing key: '%s' for block: %d.", $required, $idx); return -1; } @@ -1233,7 +1233,6 @@ protected function importTeamData(array $teamData, ?string &$message, ?array &$s $propertyAccessor = PropertyAccess::createPropertyAccessor(); foreach ($teamItem['team_affiliation'] as $field => $value) { $propertyAccessor->setValue($teamAffiliation, $field, $value); - assert($teamAffiliation instanceof TeamAffiliation); } } else { $teamAffiliation @@ -1331,7 +1330,6 @@ protected function importTeamData(array $teamData, ?string &$message, ?array &$s $propertyAccessor = PropertyAccess::createPropertyAccessor(); foreach ($teamItem['team'] as $field => $value) { $propertyAccessor->setValue($team, $field, $value); - assert($team instanceof Team); } $errors = $this->validator->validate($team); @@ -1491,7 +1489,6 @@ protected function importAccountData( $propertyAccessor = PropertyAccess::createPropertyAccessor(); foreach ($accountItem['user'] as $field => $value) { $propertyAccessor->setValue($user, $field, $value); - assert($user instanceof User); } $errors = $this->validator->validate($user); diff --git a/webapp/src/Service/ImportProblemService.php b/webapp/src/Service/ImportProblemService.php index b69a087500..2f91d270b8 100644 --- a/webapp/src/Service/ImportProblemService.php +++ b/webapp/src/Service/ImportProblemService.php @@ -229,7 +229,6 @@ public function importZippedProblem( $propertyAccessor = PropertyAccess::createPropertyAccessor(); foreach ($problemProperties as $key => $value) { $propertyAccessor->setValue($problem, $key, $value); - assert($problem instanceof Problem); } $hasErrors = false; @@ -249,7 +248,6 @@ public function importZippedProblem( if ($contestProblem !== null) { foreach ($contestProblemProperties as $key => $value) { $propertyAccessor->setValue($contestProblem, $key, $value); - assert($contestProblem instanceof ContestProblem); } $errors = $this->validator->validate($contestProblem); @@ -598,7 +596,7 @@ public function importZippedProblem( count($removedAttachments), join(',', $removedAttachments)); } - $this->em->wrapInTransaction(function () use ($testcases, $startRank) { + $this->em->wrapInTransaction(function () use ($testcases, $startRank): void { $this->em->flush(); // Set actual ranks if needed. if ($startRank !== 1) { @@ -918,7 +916,7 @@ private function searchAndAddValidator(ZipArchive $zip, array $zipEntries, ?arra } } } - if (sizeof($validatorFiles) == 0) { + if (count($validatorFiles) == 0) { if ($validationMode === 'default') { return true; } else { @@ -1089,7 +1087,6 @@ public static function parseYaml(bool|string $problemYaml, array &$messages, str foreach ($yamlProblemProperties as $key => $value) { try { $propertyAccessor->setValue($problem, $key, $value); - assert($problem instanceof Problem); } catch (Exception $e) { $messages['danger'][] = sprintf('Error: problem.%s: %s', $key, $e->getMessage()); return false; diff --git a/webapp/src/Service/RejudgingService.php b/webapp/src/Service/RejudgingService.php index 629dfc3418..872821a8ba 100644 --- a/webapp/src/Service/RejudgingService.php +++ b/webapp/src/Service/RejudgingService.php @@ -261,7 +261,7 @@ public function finishRejudging(Rejudging $rejudging, string $action, ?callable $index++; if ($action === self::ACTION_APPLY) { - $this->em->wrapInTransaction(function () use ($submission, $rejudgingId, &$scoreboardRowsToUpdate) { + $this->em->wrapInTransaction(function () use ($submission, $rejudgingId, &$scoreboardRowsToUpdate): void { // First invalidate old judging, may be different from prevjudgingid! $this->em->getConnection()->executeQuery( 'UPDATE judging SET valid=0 WHERE submitid = :submitid', diff --git a/webapp/src/Service/ScoreboardService.php b/webapp/src/Service/ScoreboardService.php index db9e99ecd7..89113a1d76 100644 --- a/webapp/src/Service/ScoreboardService.php +++ b/webapp/src/Service/ScoreboardService.php @@ -609,7 +609,7 @@ public function refreshCache(Contest $contest, ?callable $progressReporter = nul $this->dj->auditlog('contest', $contest->getCid(), 'refresh scoreboard cache'); if ($progressReporter === null) { - $progressReporter = static function (int $progress, string $log, ?string $message = null) { + $progressReporter = static function (int $progress, string $log, ?string $message = null): void { // no-op }; } diff --git a/webapp/src/Service/SubmissionService.php b/webapp/src/Service/SubmissionService.php index 010fd8e59d..2e643ff6c9 100644 --- a/webapp/src/Service/SubmissionService.php +++ b/webapp/src/Service/SubmissionService.php @@ -744,7 +744,7 @@ public function submitSolution( $this->dj->maybeCreateJudgeTasks($judging, $priority, valid: !$start_invalid); } - $this->em->wrapInTransaction(function () use ($contest, $submission) { + $this->em->wrapInTransaction(function () use ($contest, $submission): void { $this->em->flush(); $this->eventLogService->log('submission', $submission->getSubmitid(), EventLogService::ACTION_CREATE, $contest->getCid()); @@ -898,7 +898,7 @@ public function getSubmissionFileResponse(Submission $submission): StreamedRespo $filename = $file->getFilename(); $sourceCode = $file->getSourcecode(); - return new StreamedResponse(function () use ($sourceCode) { + return new StreamedResponse(function () use ($sourceCode): void { echo $sourceCode; }, 200, [ 'Content-Type' => 'text/plain', diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index 07fd305a48..90f3da039b 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -35,6 +35,8 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Serializer\SerializerInterface; +use Twig\Attribute\AsTwigFilter; +use Twig\Attribute\AsTwigFunction; use Twig\Environment; use Twig\Extension\AbstractExtension; use Twig\Extension\GlobalsInterface; @@ -42,7 +44,7 @@ use Twig\TwigFilter; use Twig\TwigFunction; -class TwigExtension extends AbstractExtension implements GlobalsInterface +class TwigExtension { public function __construct( protected readonly DOMJudgeService $dj, @@ -60,132 +62,25 @@ public function __construct( protected readonly string $projectDir, ) {} - public function getFunctions(): array + #[AsTwigFilter('base64')] + public function base64Encode(string $string): string { - return [ - new TwigFunction('button', $this->button(...), ['is_safe' => ['html']]), - new TwigFunction('calculatePenaltyTime', $this->calculatePenaltyTime(...)), - new TwigFunction('customAssetFiles', $this->customAssetFiles(...)), - new TwigFunction('globalBannerAssetPath', $this->dj->globalBannerAssetPath(...)), - new TwigFunction('shadowMode', $this->shadowMode(...)), - new TwigFunction('showDiff', $this->showDiff(...), ['is_safe' => ['html']]), - ]; - } - - public function getFilters(): array - { - return [ - new TwigFilter('printtimediff', $this->printtimediff(...)), - new TwigFilter('printelapsedminutes', $this->printelapsedminutes(...)), - new TwigFilter('printtime', $this->printtime(...)), - new TwigFilter('printHumanTimeDiff', $this->printHumanTimeDiff(...)), - new TwigFilter('printtimeHover', $this->printtimeHover(...), ['is_safe' => ['html']]), - new TwigFilter('printResult', $this->printResult(...), ['is_safe' => ['html']]), - new TwigFilter('printValidJuryResult', $this->printValidJuryResult(...), ['is_safe' => ['html']]), - new TwigFilter('printValidJurySubmissionResult', $this->printValidJurySubmissionResult(...), - ['is_safe' => ['html']]), - new TwigFilter('printHost', $this->printHost(...), ['is_safe' => ['html']]), - new TwigFilter('printHosts', $this->printHosts(...), ['is_safe' => ['html']]), - new TwigFilter('printFiles', $this->printFiles(...), ['is_safe' => ['html']]), - new TwigFilter('printLazyMode', $this->printLazyMode(...)), - new TwigFilter('printYesNo', $this->printYesNo(...)), - new TwigFilter('printSize', Utils::printSize(...), ['is_safe' => ['html']]), - new TwigFilter('testcaseResults', $this->testcaseResults(...), ['is_safe' => ['html']]), - new TwigFilter('displayTestcaseResults', $this->displayTestcaseResults(...), - ['is_safe' => ['html']]), - new TwigFilter('externalCcsUrl', $this->externalCcsUrl(...)), - new TwigFilter('lineCount', $this->lineCount(...)), - new TwigFilter('base64', 'base64_encode'), - new TwigFilter('base64_decode', 'base64_decode'), - new TwigFilter('runDiff', $this->runDiff(...), ['is_safe' => ['html']]), - new TwigFilter('interactiveLog', $this->interactiveLog(...), ['is_safe' => ['html']]), - new TwigFilter('codeEditor', $this->codeEditor(...), ['is_safe' => ['html']]), - new TwigFilter('printContestStart', $this->printContestStart(...)), - new TwigFilter('assetPath', $this->dj->assetPath(...)), - new TwigFilter('printTimeRelative', $this->printTimeRelative(...)), - new TwigFilter('scoreTime', $this->scoreTime(...)), - new TwigFilter('statusClass', $this->statusClass(...)), - new TwigFilter('statusIcon', $this->statusIcon(...), ['is_safe' => ['html']]), - new TwigFilter('countryFlag', $this->countryFlag(...), ['is_safe' => ['html']]), - new TwigFilter('affiliationLogo', $this->affiliationLogo(...), ['is_safe' => ['html']]), - new TwigFilter('descriptionExpand', $this->descriptionExpand(...), ['is_safe' => ['html']]), - new TwigFilter('wrapUnquoted', $this->wrapUnquoted(...)), - new TwigFilter('hexColorToRGBA', $this->hexColorToRGBA(...)), - new TwigFilter('tsvField', $this->toTsvField(...)), - new TwigFilter('fileTypeIcon', $this->fileTypeIcon(...)), - new TwigFilter('problemBadge', $this->problemBadge(...), ['is_safe' => ['html']]), - new TwigFilter('problemBadgeForContest', $this->problemBadgeForContest(...), ['is_safe' => ['html']]), - new TwigFilter('problemBadgeMaybe', $this->problemBadgeMaybe(...), ['is_safe' => ['html']]), - new TwigFilter('printMetadata', $this->printMetadata(...), ['is_safe' => ['html']]), - new TwigFilter('printWarningContent', $this->printWarningContent(...), ['is_safe' => ['html']]), - new TwigFilter('entityIdBadge', $this->entityIdBadge(...), ['is_safe' => ['html']]), - new TwigFilter('medalType', $this->awards->medalType(...)), - new TwigFilter('numTableActions', $this->numTableActions(...)), - new TwigFilter('extensionToMime', $this->extensionToMime(...)), - ]; + return base64_encode($string); } - public function getGlobals(): array + #[AsTwigFilter('base64_decode')] + public function base64Decode(string $string): string { - $refresh_cookie = $this->dj->getCookie("domjudge_refresh"); - $refresh_flag = ($refresh_cookie == null || (bool)$refresh_cookie); - - $user = $this->dj->getUser(); - $team = $user?->getTeam(); - - $selfRegistrationCategoriesCount = $this->em->getRepository(TeamCategory::class)->count(['allow_self_registration' => 1]); - // These variables mostly exist for the header template. - $currentContest = $this->dj->getCurrentContest(); - return [ - 'current_contest_id' => $this->dj->getCurrentContestCookie(), - 'current_contest' => $currentContest, - 'current_contests' => $this->dj->getCurrentContests(), - 'current_public_contest' => $this->dj->getCurrentContest(onlyPublic: true), - 'current_public_contests' => $this->dj->getCurrentContests(onlyPublic: true), - 'have_printing' => $this->config->get('print_command'), - 'show_languages_to_teams' => $this->config->get('show_language_versions'), - 'refresh_flag' => $refresh_flag, - 'icat_url' => $this->config->get('icat_url'), - 'external_ccs_submission_url' => $this->config->get('external_ccs_submission_url'), - 'current_team_contest' => $team ? $this->dj->getCurrentContest($team->getTeamid()) : null, - 'current_team_contests' => $team ? $this->dj->getCurrentContests($team->getTeamid()) : null, - 'submission_languages' => $this->dj->getAllowedLanguagesForContest($currentContest), - 'alpha3_countries' => Countries::getAlpha3Names(), - 'alpha3_alpha2_country_mapping' => array_combine( - Countries::getAlpha3Codes(), - array_map(fn($alpha3) => Countries::getAlpha2Code($alpha3), Countries::getAlpha3Codes()) - ), - 'show_shadow_differences' => $this->tokenStorage->getToken() && - $this->authorizationChecker->isGranted('ROLE_ADMIN') && - $this->dj->shadowMode(), - 'doc_links' => $this->dj->getDocLinks(), - 'allow_registration' => $selfRegistrationCategoriesCount !== 0, - 'enable_ranking' => $this->config->get('enable_ranking'), - 'editor_themes' => [ - 'vs' => ['name' => 'Visual Studio (light)'], - 'vs-dark' => ['name' => 'Visual Studio (dark)'], - 'Solarized-dark' => ['name' => 'Solarized (dark)', 'external' => true], - 'Solarized-light' => ['name' => 'Solarized (light)', 'external' => true], - 'Tomorrow-Night-Blue' => ['name' => 'Tomorrow Night Blue', 'external' => true], - 'Tomorrow-Night-Bright' => ['name' => 'Tomorrow Night Bright', 'external' => true], - 'Tomorrow-Night-Eighties' => ['name' => 'Tomorrow Night Eighties', 'external' => true], - 'Tomorrow-Night' => ['name' => 'Tomorrow Night', 'external' => true], - 'Tomorrow' => ['name' => 'Tomorrow', 'external' => true], - 'hc-light' => ['name' => 'High contrast (light)'], - 'hc-black' => ['name' => 'High contrast (dark)'], - ], - 'diff_modes' => [ - 'side-by-side' => ["name" => "Side-by-side"], - 'inline' => ["name" => "Inline"], - ], - ]; + return base64_decode($string); } + #[AsTwigFilter('printtimediff')] public function printtimediff(?float $start, ?float $end = null): string { return Utils::printtimediff($start, $end); } + #[AsTwigFilter('printelapsedminutes')] public function printelapsedminutes(float $start, float $end): string { $minutesElapsed = floor(($end - $start)/60); @@ -202,6 +97,7 @@ public function printelapsedminutes(float $start, float $end): string * Print a time formatted as specified. The format is according to date(). * @param bool $maskOutsideContest When true and contest is given replace time with before/after. */ + #[AsTwigFilter('printtime')] public function printtime(string|float|null $datetime, ?string $format = null, ?Contest $contest = null, bool $maskOutsideContest = true): string { if ($datetime === null) { @@ -245,6 +141,7 @@ public function printtime(string|float|null $datetime, ?string $format = null, ? } } + #[AsTwigFilter('printHumanTimeDiff')] public function printHumanTimeDiff(float|null $startTime = null, float|null $endTime = null): string { if ($startTime === null) { @@ -278,6 +175,7 @@ public function printHumanTimeDiff(float|null $startTime = null, float|null $end * * @param Contest|null $contest If given, print time relative to that contest start. */ + #[AsTwigFilter('printtimeHover', isSafe: ['html'])] public function printtimeHover(string|float $datetime, ?Contest $contest = null): string { return '%s', $class, $text); $results .= sprintf('%s', - join(', ', $titleElements), $testcase->getRank(), + join(', ', $titleElements), $testcase->getRank(), $isCorrect ? 'onclick="display_correctruns(true);"' : '', $icon); } return $results; } + #[AsTwigFilter('printResult', isSafe: ['html'])] public function printResult( ?string $result, bool $valid = true, @@ -569,11 +477,13 @@ public function printResult( return sprintf('%s', $valid ? $style : 'disabled', $result); } + #[AsTwigFilter('printValidJuryResult', isSafe: ['html'])] public function printValidJuryResult(?string $result): string { return $this->printResult($result, true, true); } + #[AsTwigFilter('printValidJurySubmissionResult', isSafe: ['html'])] public function printValidJurySubmissionResult(Submission $submission, bool $forDisplay = true): string { if ($submission->isImportError()) { @@ -618,6 +528,7 @@ public function printValidJurySubmissionResult(Submission $submission, bool $for return $output; } + #[AsTwigFilter('externalCcsUrl')] public function externalCcsUrl(Submission $submission): ?string { $extCcsUrl = $this->config->get('external_ccs_submission_url'); @@ -635,6 +546,7 @@ public function externalCcsUrl(Submission $submission): ?string * * @param Collection $files */ + #[AsTwigFilter('printFiles', isSafe: ['html'])] public function printFiles(Collection $files): string { $files = $files->toArray(); @@ -656,6 +568,7 @@ public function printFiles(Collection $files): string * Formats a given hostname. If $full = true, then the full hostname will be printed, * else only the local part (for keeping tables readable) */ + #[AsTwigFilter('printHost', isSafe: ['html'])] public function printHost(?string $hostname, bool $full = false): string { if ($hostname === null) { @@ -700,6 +613,7 @@ private function getCommonPrefix(array $strings): string * * @param string[] $hostnames */ + #[AsTwigFilter('printHosts', isSafe: ['html'])] public function printHosts(array $hostnames): string { $hostnames = array_values($hostnames); @@ -745,11 +659,13 @@ public function printHosts(array $hostnames): string } } + #[AsTwigFilter('lineCount')] public function lineCount(string $input): int { return mb_substr_count($input, "\n"); } + #[AsTwigFilter('interactiveLog', isSafe: ['html'])] public function interactiveLog(string $log, bool $forTeam = false): string { $truncated = '/\[output display truncated after \d* B\]$/'; @@ -811,6 +727,7 @@ public function interactiveLog(string $log, bool $forTeam = false): string /** * @param array{output_run: string, output_reference: string} $runOutput */ + #[AsTwigFilter('runDiff', isSafe: ['html'])] public function runDiff(array $runOutput): string { // TODO: can be improved using diffposition.txt @@ -820,9 +737,9 @@ public function runDiff(array $runOutput): string $lines_ref = preg_split('/\n/', trim($runOutput['output_reference'])); $diffs = []; - $firstErr = sizeof($lines_team) + 1; + $firstErr = count($lines_team) + 1; $lastErr = -1; - $n = min(sizeof($lines_team), sizeof($lines_ref)); + $n = min(count($lines_team), count($lines_ref)); for ($i = 0; $i < $n; $i++) { $lcs = Utils::computeLcsDiff($lines_team[$i], $lines_ref[$i]); if ($lcs[0] === true) { @@ -835,7 +752,7 @@ public function runDiff(array $runOutput): string $firstErr -= $contextLines; $lastErr += $contextLines; $firstErr = max(0, $firstErr); - $lastErr = min(sizeof($diffs) - 1, $lastErr); + $lastErr = min(count($diffs) - 1, $lastErr); $result = "
\n\n"; if ($firstErr > 0) { $result .= "\n"; @@ -843,7 +760,7 @@ public function runDiff(array $runOutput): string for ($i = $firstErr; $i <= $lastErr; $i++) { $result .= ""; } - if ($lastErr < sizeof($diffs) - 1) { + if ($lastErr < count($diffs) - 1) { $result .= "\n"; } $result .= "
[...]
" . ($i + 1) . "" . $diffs[$i] . "
[...]
\n"; @@ -858,6 +775,7 @@ public function runDiff(array $runOutput): string * @param string $elementToUpdate HTML element to update when input changes * @param string|null $filename If $language is null, filename to use to determine language */ + #[AsTwigFilter('codeEditor', isSafe: ['html'])] public function codeEditor( string $code, string $index, @@ -935,6 +853,7 @@ public function codeEditor( * source: string, * renamedFrom?: string * }> $files */ + #[AsTwigFunction('showDiff', isSafe: ['html'])] public function showDiff(string $editorId, string $diffId, int $submissionId, string $filename, array $files): string { $editor = <<config->get('score_in_seconds')); } + #[\Twig\Attribute\AsTwigFunction('calculatePenaltyTime')] public function calculatePenaltyTime(bool $solved, int $num_submissions): int { return Utils::calcPenaltyTime($solved, $num_submissions, (int)$this->config->get('penalty_time'), @@ -1039,6 +963,7 @@ public function calculatePenaltyTime(bool $solved, int $num_submissions): int /** * Print the given description, collapsing it by default if it is too big. */ + #[AsTwigFilter('descriptionExpand', isSafe: ['html'])] public function descriptionExpand(?string $description = null): string { if ($description == null) { @@ -1063,16 +988,19 @@ public function descriptionExpand(?string $description = null): string } } + #[AsTwigFunction('shadowMode')] public function shadowMode(): bool { return $this->dj->shadowMode(); } + #[AsTwigFilter('wrapUnquoted')] public function wrapUnquoted(string $text, int $width = 75, string $quote = '>'): string { return Utils::wrapUnquoted($text, $width, $quote); } + #[AsTwigFilter('hexColorToRGBA')] public function hexColorToRGBA(string $text, float $opacity = 1): string { $col = Utils::convertToHex($text); @@ -1101,11 +1029,13 @@ public function hexColorToRGBA(string $text, float $opacity = 1): string return $text; } + #[AsTwigFilter('tsvField')] public function toTsvField(string $field): string { return Utils::toTsvField($field); } + #[AsTwigFilter('fileTypeIcon')] public function fileTypeIcon(string $type): string { $iconName = match ($type) { @@ -1117,6 +1047,7 @@ public function fileTypeIcon(string $type): string return 'fas fa-file-' . $iconName; } + #[AsTwigFilter('problemBadge', isSafe: ['html'])] public function problemBadge(?ContestProblem $problem, bool $grayedOut = false): string { $rgb = Utils::convertToHex($problem?->getColor() ?? '#ffffff'); @@ -1139,6 +1070,7 @@ public function problemBadge(?ContestProblem $problem, bool $grayedOut = false): ); } + #[AsTwigFilter('problemBadgeMaybe', isSafe: ['html'])] public function problemBadgeMaybe( ContestProblem $problem, ScoreboardMatrixItem $matrixItem, @@ -1191,6 +1123,7 @@ public function problemBadgeMaybe( return $ret; } + #[AsTwigFilter('problemBadgeForContest', isSafe: ['html'])] public function problemBadgeForContest(Problem $problem, ?Contest $contest = null): string { $contest ??= $this->dj->getCurrentContest(); @@ -1198,6 +1131,7 @@ public function problemBadgeForContest(Problem $problem, ?Contest $contest = nul return $contestProblem === null ? '' : $this->problemBadge($contestProblem); } + #[AsTwigFilter('printMetadata', isSafe: ['html'])] public function printMetadata(?string $metadata): string { if ($metadata === null) { @@ -1231,6 +1165,7 @@ public function printMetadata(?string $metadata): string return $result; } + #[AsTwigFilter('printWarningContent', isSafe: ['html'])] public function printWarningContent(ExternalSourceWarning $warning): string { switch ($warning->getType()) { @@ -1301,6 +1236,7 @@ public function printWarningContent(ExternalSourceWarning $warning): string * * @param string $idPrefix The prefix to use for the internal ID, if any. */ + #[AsTwigFilter('entityIdBadge', isSafe: ['html'])] public function entityIdBadge(BaseApiEntity $entity, string $idPrefix = ''): string { $propertyAccessor = PropertyAccess::createPropertyAccessor(); @@ -1331,7 +1267,8 @@ public function entityIdBadge(BaseApiEntity $entity, string $idPrefix = ''): str * cssclass?: string * }> $tableData */ - protected function numTableActions(array $tableData): int + #[AsTwigFilter('numTableActions')] + public function numTableActions(array $tableData): int { $maxNumActions = 0; foreach ($tableData as $item) { @@ -1340,6 +1277,7 @@ protected function numTableActions(array $tableData): int return $maxNumActions; } + #[AsTwigFilter('extensionToMime')] public function extensionToMime(string $extension): string { return DOMJudgeService::EXTENSION_TO_MIMETYPE[$extension]; diff --git a/webapp/src/Twig/TwigGlobalsExtension.php b/webapp/src/Twig/TwigGlobalsExtension.php new file mode 100644 index 0000000000..5b7bac54c7 --- /dev/null +++ b/webapp/src/Twig/TwigGlobalsExtension.php @@ -0,0 +1,99 @@ + $renderedSources + */ + public function __construct( + protected readonly DOMJudgeService $dj, + protected readonly ConfigurationService $config, + protected readonly Environment $twig, + protected readonly EntityManagerInterface $em, + protected readonly SubmissionService $submissionService, + protected readonly EventLogService $eventLogService, + protected readonly AwardService $awards, + protected readonly TokenStorageInterface $tokenStorage, + protected readonly AuthorizationCheckerInterface $authorizationChecker, + protected readonly RouterInterface $router, + protected readonly SerializerInterface $serializer, + #[Autowire('%kernel.project_dir%')] + protected readonly string $projectDir, + protected array $renderedSources = [] + ) {} + + public function getGlobals(): array + { + $refresh_cookie = $this->dj->getCookie("domjudge_refresh"); + $refresh_flag = ($refresh_cookie == null || (bool)$refresh_cookie); + + $user = $this->dj->getUser(); + $team = $user?->getTeam(); + + $selfRegistrationCategoriesCount = $this->em->getRepository(TeamCategory::class)->count(['allow_self_registration' => 1]); + // These variables mostly exist for the header template. + $currentContest = $this->dj->getCurrentContest(); + return [ + 'current_contest_id' => $this->dj->getCurrentContestCookie(), + 'current_contest' => $currentContest, + 'current_contests' => $this->dj->getCurrentContests(), + 'current_public_contest' => $this->dj->getCurrentContest(onlyPublic: true), + 'current_public_contests' => $this->dj->getCurrentContests(onlyPublic: true), + 'have_printing' => $this->config->get('print_command'), + 'show_languages_to_teams' => $this->config->get('show_language_versions'), + 'refresh_flag' => $refresh_flag, + 'icat_url' => $this->config->get('icat_url'), + 'external_ccs_submission_url' => $this->config->get('external_ccs_submission_url'), + 'current_team_contest' => $team ? $this->dj->getCurrentContest($team->getTeamid()) : null, + 'current_team_contests' => $team ? $this->dj->getCurrentContests($team->getTeamid()) : null, + 'submission_languages' => $this->dj->getAllowedLanguagesForContest($currentContest), + 'alpha3_countries' => Countries::getAlpha3Names(), + 'alpha3_alpha2_country_mapping' => array_combine( + Countries::getAlpha3Codes(), + array_map(fn($alpha3) => Countries::getAlpha2Code($alpha3), Countries::getAlpha3Codes()) + ), + 'show_shadow_differences' => $this->tokenStorage->getToken() && + $this->authorizationChecker->isGranted('ROLE_ADMIN') && + $this->dj->shadowMode(), + 'doc_links' => $this->dj->getDocLinks(), + 'allow_registration' => $selfRegistrationCategoriesCount !== 0, + 'enable_ranking' => $this->config->get('enable_ranking'), + 'editor_themes' => [ + 'vs' => ['name' => 'Visual Studio (light)'], + 'vs-dark' => ['name' => 'Visual Studio (dark)'], + 'Solarized-dark' => ['name' => 'Solarized (dark)', 'external' => true], + 'Solarized-light' => ['name' => 'Solarized (light)', 'external' => true], + 'Tomorrow-Night-Blue' => ['name' => 'Tomorrow Night Blue', 'external' => true], + 'Tomorrow-Night-Bright' => ['name' => 'Tomorrow Night Bright', 'external' => true], + 'Tomorrow-Night-Eighties' => ['name' => 'Tomorrow Night Eighties', 'external' => true], + 'Tomorrow-Night' => ['name' => 'Tomorrow Night', 'external' => true], + 'Tomorrow' => ['name' => 'Tomorrow', 'external' => true], + 'hc-light' => ['name' => 'High contrast (light)'], + 'hc-black' => ['name' => 'High contrast (dark)'], + ], + 'diff_modes' => [ + 'side-by-side' => ["name" => "Side-by-side"], + 'inline' => ["name" => "Inline"], + ], + ]; + } +} diff --git a/webapp/src/Utils/Adminer.php b/webapp/src/Utils/Adminer.php deleted file mode 100644 index ad7d58d3dc..0000000000 --- a/webapp/src/Utils/Adminer.php +++ /dev/null @@ -1,80 +0,0 @@ -getDatabaseCredentials()['db']; - } - - public function databases($flush = true): array - { - return [$this->getDatabaseCredentials()['db']]; - } - - public function credentials(): array - { - ['host' => $host, 'user' => $user, 'pass' => $pass] = $this->getDatabaseCredentials(); - - return [$host, $user, $pass]; - } - - public function login($login, $password): bool - { - return true; - } - - public function tableName($tableStatus): string - { - return h($tableStatus['Name']); - } - - public function permanentLogin($create = false): string - { - return 'domjudge'; - } - - public function loginForm(): void - { - ['db' => $db, 'user' => $user] = $this->getDatabaseCredentials(); - echo ""; - echo ""; - echo ""; - echo "

\n"; - } - - /** - * @return array{host: string, db: string, user: string, pass: string} - */ - private function getDatabaseCredentials(): array - { - $host = $db = $user = $pass = null; - - // Load credentials from /dbpasswords.secret - $dbsecretsfile = $GLOBALS['etcDir'] . '/dbpasswords.secret'; - $db_credentials = file($dbsecretsfile); - foreach ($db_credentials as $line) { - if ($line[0] == '#') { - continue; - } - [$_, $host, $db, $user, $pass] = array_pad(explode(':', trim($line)), 6, null); - break; - } - - if ($host === null) { - throw new \LogicException("Can't get DB credentials"); - } - - return ['host' => $host, 'db' => $db, 'user' => $user, 'pass' => $pass]; - } -} diff --git a/webapp/src/Utils/Utils.php b/webapp/src/Utils/Utils.php index 9e07e13944..3a5f7a189c 100644 --- a/webapp/src/Utils/Utils.php +++ b/webapp/src/Utils/Utils.php @@ -6,6 +6,7 @@ use enshrined\svgSanitize\Sanitizer as SvgSanitizer; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Twig\Attribute\AsTwigFilter; /** * Generic utility class. @@ -510,6 +511,7 @@ public static function printhost(string $hostname, bool $full = false): string * Print (file) size in human-readable format by using B,KB,MB,GB suffixes. * Input is an integer (the size in bytes), output a string with suffix. */ + #[AsTwigFilter('printSize', isSafe: ['html'])] public static function printsize(int $size, int $decimals = 1): string { $factor = 1024; @@ -600,8 +602,8 @@ public static function computeLcsDiff(string $line1, string $line2): array $tokens2 = preg_split('/\s+/', $line2); $cutoff = 100; // a) LCS gets in-performant, b) the output is no longer readable. - $n1 = min($cutoff, sizeof($tokens1)); - $n2 = min($cutoff, sizeof($tokens2)); + $n1 = min($cutoff, count($tokens1)); + $n2 = min($cutoff, count($tokens2)); // compute longest common sequence length $dp = array_fill(0, $n1+1, array_fill(0, $n2+1, 0)); @@ -638,7 +640,7 @@ public static function computeLcsDiff(string $line1, string $line2): array // Reconstruct diff. $diff = ""; - $l = sizeof($lcs); + $l = count($lcs); $i = 0; $j = 0; for ($k = 0; $k < $l; $k++) { @@ -663,7 +665,7 @@ public static function computeLcsDiff(string $line1, string $line2): array $j++; } - if ($cutoff < sizeof($tokens1) || $cutoff < sizeof($tokens2)) { + if ($cutoff < count($tokens1) || $cutoff < count($tokens2)) { $diff .= "[cut off rest of line...]"; } $diff .= "\n"; @@ -910,7 +912,7 @@ public static function tableForEntity(object $entity): string public static function streamAsBinaryFile(string $content, string $filename, string $type = 'octet-stream'): StreamedResponse { $response = new StreamedResponse(); - $response->setCallback(function () use ($content) { + $response->setCallback(function () use ($content): void { echo $content; }); $response->headers->set('Content-Type', 'application/' . $type); @@ -926,7 +928,7 @@ public static function streamAsBinaryFile(string $content, string $filename, str public static function streamZipFile(string $tempFilename, string $zipFilename): StreamedResponse { $response = new StreamedResponse(); - $response->setCallback(function () use ($tempFilename) { + $response->setCallback(function () use ($tempFilename): void { $fp = fopen($tempFilename, 'rb'); fpassthru($fp); unlink($tempFilename); @@ -976,7 +978,7 @@ public static function parseTsvLine(string $line): array public static function reindex(array $array, callable $callback): array { $reindexed = []; - array_walk($array, function ($item, $key) use (&$reindexed, $callback) { + array_walk($array, function ($item, $key) use (&$reindexed, $callback): void { $reindexed[$callback($item, $key)] = $item; }); return $reindexed; @@ -1029,7 +1031,7 @@ public static function getTextStreamedResponse( }; $response = new StreamedResponse(); - $response->setCallback(function () use ($text) { + $response->setCallback(function () use ($text): void { echo $text; }); $response->headers->set('Content-Type', sprintf('%s; name="%s"', $mimetype, $filename)); diff --git a/webapp/symfony.lock b/webapp/symfony.lock index 963b9998a9..6873fe6465 100644 --- a/webapp/symfony.lock +++ b/webapp/symfony.lock @@ -17,15 +17,9 @@ "dflydev/dot-access-data": { "version": "v3.0.1" }, - "doctrine/cache": { - "version": "v1.8.0" - }, "doctrine/collections": { "version": "v1.6.2" }, - "doctrine/common": { - "version": "v2.10.0" - }, "doctrine/data-fixtures": { "version": "v1.3.2" }, @@ -555,9 +549,6 @@ "symfony/polyfill-mbstring": { "version": "v1.11.0" }, - "symfony/polyfill-php72": { - "version": "v1.11.0" - }, "symfony/polyfill-php80": { "version": "v1.17.1" }, diff --git a/webapp/templates/jury/external_contest_manage.html.twig b/webapp/templates/jury/external_contest_manage.html.twig index 6481cd66c5..bea7470e9c 100644 --- a/webapp/templates/jury/external_contest_manage.html.twig +++ b/webapp/templates/jury/external_contest_manage.html.twig @@ -41,7 +41,7 @@ var typeChanged = function () { var ccsApiFields = $('[data-type-ccs-api]'); switch (type.val()) { - case '{{ constant('\App\\Entity\\ExternalContestSource::TYPE_CCS_API') }}': + case '{{ constant('\\App\\Entity\\ExternalContestSource::TYPE_CCS_API') }}': ccsApiFields.show(); break; default: diff --git a/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php b/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php index 9e1a9ed5de..9ff40c7131 100644 --- a/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php +++ b/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php @@ -2,10 +2,9 @@ namespace App\Tests\Unit\Command; -use App\Command\ResetUserPasswordCommand; use App\Tests\Unit\BaseTestCase as BaseTestCase; use Symfony\Bundle\FrameworkBundle\Console\Application; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\LazyCommand; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; @@ -19,7 +18,7 @@ class ResetUserPasswordCommandTest extends BaseTestCase public static string $demoPassword = 'demo'; public static string $commandName = 'domjudge:reset-user-password'; protected Application $app; - protected ResetUserPasswordCommand $command; + protected Command $command; protected CommandTester $commandTester; protected function setUp(): void @@ -28,9 +27,7 @@ protected function setUp(): void $this->app = new Application(self::$kernel); /** @var LazyCommand $command */ $command = $this->app->find(static::$commandName); - /** @var ResetUserPasswordCommand $resetCommand */ - $resetCommand = $command->getCommand(); - $this->command = $resetCommand; + $this->command = $command->getCommand(); $this->commandTester = new CommandTester($this->command); } diff --git a/webapp/tests/Unit/Controller/API/ClarificationControllerTest.php b/webapp/tests/Unit/Controller/API/ClarificationControllerTest.php index cb02f0099b..39d89e5a2d 100644 --- a/webapp/tests/Unit/Controller/API/ClarificationControllerTest.php +++ b/webapp/tests/Unit/Controller/API/ClarificationControllerTest.php @@ -142,7 +142,7 @@ public function testAddInvalidData(string $user, array $dataToSend, string $expe public function provideAddInvalidData(): Generator { - yield ['demo', [], ""]; + yield ['demo', [], 'Request payload contains invalid "json" data.']; yield ['demo', ['invalidfield' => 'value'], "/text:\n.*This value should be of type string./"]; yield ['demo', ['text' => 'This is a clarification', 'from_team_id' => 'domjudge'], "Can not create a clarification from a different team."]; yield ['demo', ['text' => 'This is a clarification', 'to_team_id' => 'exteam'], "Can not create a clarification that is sent to a team."]; diff --git a/webapp/tests/Unit/Controller/API/SubmissionControllerTest.php b/webapp/tests/Unit/Controller/API/SubmissionControllerTest.php index 1bfe4fba36..662935320a 100644 --- a/webapp/tests/Unit/Controller/API/SubmissionControllerTest.php +++ b/webapp/tests/Unit/Controller/API/SubmissionControllerTest.php @@ -92,7 +92,7 @@ public function testAddInvalidData(string $user, array $dataToSend, string $expe public function provideAddInvalidData(): Generator { - yield ['demo', [], ""]; + yield ['demo', [], 'Request payload contains invalid "json" data.']; yield ['demo', ['unknown_key'], "/One of the arguments 'problem', 'problem_id' is required/"]; yield ['demo', ['problem' => 'hello'], "/One of the arguments 'language', 'language_id' is required/"]; yield ['demo', ['problem_id' => 'hello'], "/One of the arguments 'language', 'language_id' is required/"]; diff --git a/webapp/tests/Unit/Service/ConfigurationServiceTest.php b/webapp/tests/Unit/Service/ConfigurationServiceTest.php index c0b2de5cef..7b82e6d220 100644 --- a/webapp/tests/Unit/Service/ConfigurationServiceTest.php +++ b/webapp/tests/Unit/Service/ConfigurationServiceTest.php @@ -6,7 +6,7 @@ use App\Entity\Executable; use App\Service\ConfigurationService; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\Persistence\ObjectRepository; +use Doctrine\ORM\EntityRepository; use Exception; use Generator; use PHPUnit\Framework\MockObject\Builder\InvocationMocker; @@ -24,9 +24,9 @@ class ConfigurationServiceTest extends KernelTestCase private ?EntityManagerInterface $em; /** - * @var ObjectRepository&MockObject + * @var EntityRepository&MockObject */ - private ObjectRepository&MockObject $configRepository; + private EntityRepository&MockObject $configRepository; private InvocationMocker $emGetRepositoryExpects; @@ -43,7 +43,7 @@ protected function setUp(): void self::bootKernel(); $this->em = $this->createMock(EntityManagerInterface::class); - $this->configRepository = $this->createMock(ObjectRepository::class); + $this->configRepository = $this->createMock(EntityRepository::class); $this->emGetRepositoryExpects = $this->em->expects(self::any()) ->method('getRepository') ->willReturnMap([[Configuration::class, $this->configRepository]]); @@ -298,7 +298,7 @@ public function testAddOptionsExecutables(string $item, array $expected): void throw new Exception("Item value should be default_{compare,run}."); } - $execRepository = $this->createMock(ObjectRepository::class); + $execRepository = $this->createMock(EntityRepository::class); $this->emGetRepositoryExpects ->willReturnMap([[Configuration::class, $this->configRepository], [Executable::class, $execRepository]]);