diff --git a/.appveyor.yml b/.appveyor.yml
index 35847e4fc3727..b8ca657e6ffc0 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -12,7 +12,6 @@ init:
- SET SYMFONY_DEPRECATIONS_HELPER=strict
- SET ANSICON=121x90 (121x90)
- SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1
- - SET SYMFONY_DEPRECATIONS_HELPER=max[direct]=1
- REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f
install:
@@ -20,8 +19,10 @@ install:
- appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.2.5-Win32-VC15-x86.zip
- 7z x php-7.2.5-Win32-VC15-x86.zip -y >nul
- cd ext
- - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.17-7.2-ts-vc15-x86.zip
- - 7z x php_apcu-5.1.17-7.2-ts-vc15-x86.zip -y >nul
+ - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.19-7.2-ts-vc15-x86.zip
+ - 7z x php_apcu-5.1.19-7.2-ts-vc15-x86.zip -y >nul
+ - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_redis-5.3.2-7.2-ts-vc15-x86.zip
+ - 7z x php_redis-5.3.2-7.2-ts-vc15-x86.zip -y >nul
- cd ..
- copy /Y php.ini-development php.ini-min
- echo memory_limit=-1 >> php.ini-min
@@ -37,6 +38,7 @@ install:
- echo opcache.enable_cli=1 >> php.ini-max
- echo extension=php_openssl.dll >> php.ini-max
- echo extension=php_apcu.dll >> php.ini-max
+ - echo extension=php_redis.dll >> php.ini-max
- echo apc.enable_cli=1 >> php.ini-max
- echo extension=php_intl.dll >> php.ini-max
- echo extension=php_mbstring.dll >> php.ini-max
@@ -55,6 +57,7 @@ install:
- SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev
- php composer.phar update --no-progress --ansi
- php phpunit install
+ - choco install memurai-developer
test_script:
- SET X=0
@@ -62,9 +65,9 @@ test_script:
- copy /Y c:\php\php.ini-min c:\php\php.ini
- IF %APPVEYOR_REPO_BRANCH:~-2% neq .x (rm -Rf src\Symfony\Bridge\PhpUnit)
- mv src\Symfony\Component\HttpClient\phpunit.xml.dist src\Symfony\Component\HttpClient\phpunit.xml
- - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data || SET X=!errorlevel!
+ - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel!
- php phpunit src\Symfony\Component\HttpClient || SET X=!errorlevel!
- copy /Y c:\php\php.ini-max c:\php\php.ini
- - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data || SET X=!errorlevel!
+ - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel!
- php phpunit src\Symfony\Component\HttpClient || SET X=!errorlevel!
- exit %X%
diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.md b/.github/ISSUE_TEMPLATE/1_Bug_report.md
deleted file mode 100644
index aef16611e0f77..0000000000000
--- a/.github/ISSUE_TEMPLATE/1_Bug_report.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-name: 🐛 Bug Report
-about: ⚠️ See below for security reports
-labels: Bug
-
----
-
-**Symfony version(s) affected**: x.y.z
-
-**Description**
-
-
-**How to reproduce**
-
-
-**Possible Solution**
-
-
-**Additional context**
-
diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml
index 5518d4e4ad79d..ef0f72c794278 100644
--- a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml
@@ -1,5 +1,5 @@
name: 🐛 Bug Report
-description: ⚠️ See below for security reports
+description: ⚠️ NEVER report security issues, read https://symfony.com/security instead
labels: Bug
body:
@@ -14,7 +14,7 @@ body:
id: description
attributes:
label: Description
- description: A clear and consise description of the problem
+ description: A clear and concise description of the problem
validations:
required: true
- type: textarea
@@ -22,15 +22,21 @@ body:
attributes:
label: How to reproduce
description: |
- Code and/or config needed to reproduce the problem.
- If it's a complex bug, create a "bug reproducer" as explained in https://symfony.com/doc/current/contributing/code/reproducer.html
+ ⚠️ This is the most important part of the report ⚠️
+ Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix.
+ Please, take the time to show us some code and/or config that is needed for others to reproduce the problem easily.
+ Most of the time, creating a "bug reproducer" as explained in the URL below is the best way to help us
+ and increases the chances someone will have a look at it:
+ https://symfony.com/doc/current/contributing/code/reproducer.html
validations:
required: true
- type: textarea
id: possible-solution
attributes:
label: Possible Solution
- description: "Optional: only if you have suggestions on a fix/reason for the bug"
+ description: |
+ Optional: only if you have suggestions on a fix/reason for the bug
+ Don't hesitate to create a pull request with your solution, it helps get faster feedback.
- type: textarea
id: additional-context
attributes:
diff --git a/.github/ISSUE_TEMPLATE/2_Feature_request.md b/.github/ISSUE_TEMPLATE/2_Feature_request.md
deleted file mode 100644
index 908c5ee52664d..0000000000000
--- a/.github/ISSUE_TEMPLATE/2_Feature_request.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-name: 🚀 Feature Request
-about: RFC and ideas for new features and improvements
-
----
-
-**Description**
-
-
-**Example**
-
diff --git a/.github/ISSUE_TEMPLATE/3_Support_question.md b/.github/ISSUE_TEMPLATE/3_Support_question.md
deleted file mode 100644
index 9480710c15655..0000000000000
--- a/.github/ISSUE_TEMPLATE/3_Support_question.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-name: ⛔ Support Question
-about: See https://symfony.com/support for questions about using Symfony and its components
-
----
-
-We use GitHub issues only to discuss about Symfony bugs and new features. For
-this kind of questions about using Symfony or third-party bundles, please use
-any of the support alternatives shown in https://symfony.com/support
-
-Thanks!
diff --git a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md b/.github/ISSUE_TEMPLATE/4_Documentation_issue.md
deleted file mode 100644
index 0855c3c5f1e12..0000000000000
--- a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-name: ⛔ Documentation Issue
-about: See https://github.com/symfony/symfony-docs/issues for documentation issues
-
----
-
-Symfony Documentation has its own dedicated repository. Please open your
-documentation-related issue at https://github.com/symfony/symfony-docs/issues
-
-Thanks!
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000000..34227566ed84a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Support Question
+ url: https://symfony.com/support
+ about: We use GitHub issues only to discuss about Symfony bugs and new features. For this kind of questions about using Symfony or third-party bundles, please use any of the support alternatives shown in https://symfony.com/support
+ - name: Documentation Issue
+ url: https://github.com/symfony/symfony-docs/issues
+ about: Symfony Documentation has its own dedicated repository.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 62662f876fd3a..5e7092d385910 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,6 @@
| Q | A
| ------------- | ---
-| Branch? | 5.4 for features / 4.4 or 5.3 for bug fixes
+| Branch? | 6.1 for features / 4.4, 5.3, 5.4 or 6.0 for bug fixes
| Bug fix? | yes/no
| New feature? | yes/no
| Deprecations? | yes/no
@@ -8,14 +8,14 @@
| License | MIT
| Doc PR | symfony/symfony-docs#...
diff --git a/.github/get-modified-packages.php b/.github/get-modified-packages.php
index 9135a1da666e5..a3682af0b9d1a 100644
--- a/.github/get-modified-packages.php
+++ b/.github/get-modified-packages.php
@@ -17,9 +17,33 @@
return strlen($b) <=> strlen($a) ?: $a <=> $b;
});
-function isComponentBridge(string $packageDir): bool
+function getPackageType(string $packageDir): string
{
- return 0 < preg_match('@Symfony/Component/.*/Bridge/@', $packageDir);
+ if (preg_match('@Symfony/Bridge/@', $packageDir)) {
+ return 'bridge';
+ }
+
+ if (preg_match('@Symfony/Bundle/@', $packageDir)) {
+ return 'bundle';
+ }
+
+ if (preg_match('@Symfony/Component/[^/]+/Bridge/@', $packageDir)) {
+ return 'component_bridge';
+ }
+
+ if (preg_match('@Symfony/Component/@', $packageDir)) {
+ return 'component';
+ }
+
+ if (preg_match('@Symfony/Contracts/@', $packageDir)) {
+ return 'contract';
+ }
+
+ if (preg_match('@Symfony/Contracts$@', $packageDir)) {
+ return 'contracts';
+ }
+
+ throw new \LogicException();
}
$newPackage = [];
@@ -43,7 +67,7 @@ function isComponentBridge(string $packageDir): bool
$output = [];
foreach ($modifiedPackages as $directory => $bool) {
$name = json_decode(file_get_contents($directory.'/composer.json'), true)['name'] ?? 'unknown';
- $output[] = ['name' => $name, 'directory' => $directory, 'new' => $newPackage[$directory] ?? false, 'component_bridge' => isComponentBridge($directory)];
+ $output[] = ['name' => $name, 'directory' => $directory, 'new' => $newPackage[$directory] ?? false, 'type' => getPackageType($directory)];
}
echo json_encode($output);
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index b3f3d6cba8d2a..c41b6a2be6b12 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -157,8 +157,6 @@ jobs:
- name: Run tests
run: ./phpunit --group integration -v
env:
- SYMFONY_DEPRECATIONS_HELPER: max[direct]=1 # to be removed once DbalLogger is compatible with dbal 3.2+
- REDIS_HOST: localhost
REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005'
REDIS_SENTINEL_HOSTS: 'localhost:26379'
REDIS_SENTINEL_SERVICE: redis_sentinel
@@ -166,10 +164,6 @@ jobs:
MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages
MESSENGER_SQS_DSN: "sqs://localhost:9494/messages?sslmode=disable&poll_timeout=0.01"
MESSENGER_SQS_FIFO_QUEUE_DSN: "sqs://localhost:9494/messages.fifo?sslmode=disable&poll_timeout=0.01"
- MEMCACHED_HOST: localhost
- LDAP_HOST: localhost
- LDAP_PORT: 3389
- MONGODB_HOST: localhost
KAFKA_BROKER: 127.0.0.1:9092
POSTGRES_HOST: localhost
diff --git a/.github/workflows/package-tests.yml b/.github/workflows/package-tests.yml
index cb66e2d8d3b03..3c0a7c36be89f 100644
--- a/.github/workflows/package-tests.yml
+++ b/.github/workflows/package-tests.yml
@@ -63,13 +63,18 @@ jobs:
DIR=$(_jq '.directory')
NAME=$(_jq '.name')
echo "::group::$NAME"
+ TYPE=$(_jq '.type')
localExit=0
- _file_exist $DIR/.gitattributes || localExit=1
+ if [ $TYPE != 'contract' ] && [ $TYPE != 'contracts' ]; then
+ _file_exist $DIR/.gitattributes || localExit=1
+ fi
_file_exist $DIR/.gitignore || localExit=1
_file_exist $DIR/CHANGELOG.md || localExit=1
_file_exist $DIR/LICENSE || localExit=1
- _file_exist $DIR/phpunit.xml.dist || localExit=1
+ if [ $TYPE != 'contract' ]; then
+ _file_exist $DIR/phpunit.xml.dist || localExit=1
+ fi
_file_exist $DIR/README.md || localExit=1
_file_not_exist $DIR/phpunit.xml || localExit=1
@@ -77,7 +82,7 @@ jobs:
echo "Verifying new package"
_correct_license_file $DIR/LICENSE || localExit=1
- if [ $(_jq '.component_bridge') == false ]; then
+ if [ $TYPE == 'component_bridge' ]; then
if [ ! $(cat composer.json | jq -e ".replace.\"$NAME\"|test(\"self.version\")") ]; then
echo "Composer.json's replace section needs to contain $NAME"
localExit=1
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index edd59d3f188f6..a208a253456e2 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -12,7 +12,6 @@ jobs:
tests:
name: Tests
- runs-on: Ubuntu-20.04
env:
extensions: amqp,apcu,igbinary,intl,mbstring,memcached,redis-5.3.4
@@ -21,15 +20,17 @@ jobs:
matrix:
include:
- php: '7.2'
- - php: '8.1'
- php: '7.4'
- mode: high-deps
- php: '8.0'
+ mode: high-deps
+ - php: '8.1'
mode: low-deps
- php: '8.2'
mode: experimental
fail-fast: false
+ runs-on: ubuntu-20.04
+
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -61,12 +62,11 @@ jobs:
([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json"
echo COLUMNS=120 >> $GITHUB_ENV
- echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV
+ echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV
echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV
- echo SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 >> $GITHUB_ENV # to be removed once DbalLogger is compatible with dbal 3.2+
SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V)
- SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+')
+ SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | cut -d "'" -f2 | cut -d '.' -f 1-2)
SYMFONY_FEATURE_BRANCH=$(curl -s https://raw.githubusercontent.com/symfony/recipes/flex/main/index.json | jq -r '.versions."dev-name"')
# Install the phpunit-bridge from a PR if required
@@ -112,9 +112,9 @@ jobs:
# Skip the phpunit-bridge on bugfix-branches when not in *-deps mode
if [[ ! "${{ matrix.mode }}" = *-deps && $SYMFONY_VERSION != $SYMFONY_FEATURE_BRANCH ]]; then
- echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h ') >> $GITHUB_ENV
+ echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' | xargs -I{} dirname {}) >> $GITHUB_ENV
else
- echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h ') >> $GITHUB_ENV
+ echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist | xargs -I{} dirname {}) >> $GITHUB_ENV
fi
# Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one
@@ -173,19 +173,21 @@ jobs:
exit 0
fi
- (cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb)
-
if [[ "${{ matrix.mode }}" = low-deps ]]; then
echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT'"
exit 0
fi
+ (cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb)
+ (cd src/Symfony/Component/Lock; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb)
+
# matrix.mode = high-deps
echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1
# get a list of the patched components (relies on .github/build-packages.php being called in the previous step)
(cd src/Symfony/Component/HttpFoundation; mv composer.bak composer.json)
+ (cd src/Symfony/Component/Lock; mv composer.bak composer.json)
PATCHED_COMPONENTS=$(git diff --name-only src/ | grep composer.json || true)
# for 5.4 LTS, checkout and test previous major with the patched components (only for patched components)
@@ -199,6 +201,7 @@ jobs:
git checkout -m FETCH_HEAD
PATCHED_COMPONENTS=$(echo "$PATCHED_COMPONENTS" | xargs dirname | xargs -n1 -I{} bash -c "[ -e '{}/phpunit.xml.dist' ] && echo '{}'" | sort || true)
(cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb)
+ (cd src/Symfony/Component/Lock; composer require --dev --no-update mongodb/mongodb)
if [[ $PATCHED_COMPONENTS ]]; then
echo "::group::install phpunit"
./phpunit install
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index cfe2bb4456738..8e7e3f129f7e1 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -11,6 +11,7 @@
'@Symfony' => true,
'@Symfony:risky' => true,
'protected_to_private' => false,
+ 'native_constant_invocation' => ['strict' => false],
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false],
])
->setRiskyAllowed(true)
diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md
index ceeefa8cad098..0436dd92be510 100644
--- a/CHANGELOG-5.3.md
+++ b/CHANGELOG-5.3.md
@@ -7,6 +7,69 @@ in 5.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.3.0...v5.3.1
+* 5.3.13 (2021-12-29)
+
+ * bug #44838 [DependencyInjection][HttpKernel] Fix enum typed bindings (ogizanagi)
+ * bug #44723 [Lock] Release PostgreSqlStore connection lock on failure (simon-watiau) * commit 'e5b2f9efba': [Lock] Release PostgreSqlStore connection lock on failure
+ * bug #44826 [HttpKernel] Do not attempt to register enum arguments in controller service locator (ogizanagi)
+ * bug #44824 [Mime] Fix missing sprintf in DkimSigner (alamirault)
+ * bug #44816 [Translation] [LocoProvider] Use rawurlencode and separate tag setting (danut007ro)
+ * bug #44805 [Security] fix unserializing session payloads from v4 (nicolas-grekas)
+ * bug #44820 [Cache] Don't lock when doing nested computations (nicolas-grekas)
+ * bug #44807 [Messenger] fix Redis support on 32b arch (nicolas-grekas)
+ * bug #44759 [HttpFoundation] Fix notice when HTTP_PHP_AUTH_USER passed without pass (Vitali Tsyrkin)
+ * bug #44799 [Cache] fix compat with apcu < 5.1.10 (nicolas-grekas)
+ * bug #44085 [Translation] Fix TranslationPullCommand with ICU translations (Kocal)
+ * bug #44771 [Notifier] Use correct factory for the msteams transport (veewee)
+ * bug #44618 [HttpKernel] Fix SessionListener without session in request (shyim)
+ * bug #44743 [HttpClient] fix checking for recent curl consts (nicolas-grekas)
+ * bug #44752 [Security/Http] Fix cookie clearing on logout (maxhelias)
+ * bug #44732 [Mime] Relaxing in-reply-to header validation (ThomasLandauer)
+ * bug #44728 [Mime] Fix encoding filenames in multipart/form-data (nicolas-grekas)
+ * bug #44710 [DependencyInjection] fix linting callable classes (nicolas-grekas)
+ * bug #44639 [DependencyInjection] Cast tag attribute value to string (ruudk)
+ * bug #44473 [Validator] Restore default locale in ConstraintValidatorTestCase (rodnaph)
+ * bug #44682 [FrameworkBundle] alias `cache.app.taggable` to `cache.app` if using `cache.adapter.redis_tag_aware` (kbond)
+ * bug #44671 [HttpClient] Fix tracing requests made after calling withOptions() (nicolas-grekas)
+ * bug #44577 [Cache] Fix proxy no expiration to the Redis (Sergey Belyshkin)
+ * bug #44669 [Cache] disable lock on CLI (nicolas-grekas)
+ * bug #44598 [Translation] Handle the blank-translation in Loco Adapter (kgonella)
+ * bug #44354 [RateLimiter] Make RateLimiter resilient to timeShifting (jderusse)
+ * bug #44600 [Serializer] Fix denormalizing custom class in UidNormalizer (fancyweb)
+ * bug #44537 [Config] In XmlUtils, avoid converting from octal every string starting with a 0 (alexandre-daubois)
+ * bug #44510 [Workflow] Fix eventsToDispatch parameter setup for StateMachine (Olexandr Kalaidzhy)
+ * bug #44625 [HttpClient] fix monitoring responses issued before reset() (nicolas-grekas)
+ * bug #44623 [HttpClient] Fix dealing with "HTTP/1.1 000 " responses (nicolas-grekas)
+ * bug #44601 [HttpClient] Fix closing curl-multi handle too early on destruct (nicolas-grekas)
+ * bug #44571 [HttpClient] Don't reset timeout counter when initializing requests (nicolas-grekas)
+ * bug #44479 [HttpClient] Double check if handle is complete (Nyholm)
+ * bug #44418 [DependencyInjection] Resolve ChildDefinition in AbstractRecursivePass (fancyweb)
+ * bug #44474 [Translation] [Bridge] [Lokalise] Fix push keys to lokalise. Closes #… (olegmifle)
+ * bug #43164 [FrameworkBundle] Fix cache pool configuration with one adapter and one provider (fancyweb)
+ * bug #44419 [PropertyAccess] Fix accessing public property on Object (kevcomparadise)
+ * bug #44565 [FrameworkBundle] Use correct cookie domain in loginUser() (wouterj)
+ * bug #44538 [Process] fixed uppercase ARGC and ARGV should also be skipped (rbaarsma)
+ * bug #44438 [HttpClient] Fix handling thrown \Exception in \Generator in MockResponse (fancyweb)
+ * bug #44469 [String] Fix requiring wcswitch table several times (fancyweb)
+ * bug #44502 [HttpFoundation] do not call preg_match() on null (xabbuh)
+ * bug #44481 [FrameworkBundle] Fix loginUser() causing deprecation (wouterj)
+ * bug #44416 [Translation] Make http requests synchronous when reading the Loco API (Kocal)
+ * bug #44350 [Translation] Fix TranslationTrait (Tomasz Kusy)
+ * bug #44467 [Console] Fix parameter types for `ProcessHelper::mustRun()` (derrabus)
+ * bug #44427 [FrameworkBundle] Fix compatibility with symfony/security-core 6.x (deps=high tests) (wouterj)
+ * bug #44399 Prevent infinite nesting of lazy `ObjectManager` instances when `ObjectManager` is reset (Ocramius)
+ * bug #44375 [DoctrineBridge] fix calling get_class on non-object (kbond)
+ * bug #44361 [HttpClient] Fix handling error info in MockResponse (fancyweb)
+ * bug #44309 [Messenger] Leverage DBAL's getNativeConnection() method (derrabus)
+ * bug #44187 [Translation] [Loco] Fix idempotency of LocoProvider write method (welcoMattic)
+ * bug #43992 [Security] Do not overwrite already stored tokens for REMOTE_USER authentication (stlrnz)
+ * bug #43876 [Validator] Fix validation for single level domains (HypeMC)
+ * bug #44327 [Debug][ErrorHandler] Increased the reserved memory from 10k to 32k (sakalys)
+ * bug #44261 [Process] intersect with getenv() in case-insensitive manner to get default envs (stable-staple)
+ * bug #44295 [Serializer] fix support for lazy/unset properties (nicolas-grekas)
+ * bug #44277 [Notifier] Fix AllMySms bridge body content (afiocre)
+ * bug #44269 [DoctrineBridge] Revert " add support for the JSON type" (dunglas)
+
* 5.3.12 (2021-11-24)
* security #cve-2021-41268 [SecurityBundle] Default signature_properties to the previous behavior (wouterj)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 92b9b528b9c50..b5e87ad1280f4 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -12,8 +12,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Tobias Schultze (tobion)
- Robin Chalas (chalas_r)
- Christophe Coevoet (stof)
- - Wouter De Jong (wouterj)
- Jérémy DERUSSÉ (jderusse)
+ - Wouter De Jong (wouterj)
- Grégoire Pineau (lyrixx)
- Maxime Steinhausser (ogizanagi)
- Kévin Dunglas (dunglas)
@@ -58,9 +58,9 @@ The Symfony Connect username in parenthesis allows to get more information
- Diego Saint Esteben (dosten)
- Grégoire Paris (greg0ire)
- Alexandre Salomé (alexandresalome)
+ - Jérôme Tamarelle (gromnan)
- William Durand (couac)
- ornicar
- - Jérôme Tamarelle (gromnan)
- Konstantin Myakshin (koc)
- Dany Maillard (maidmaid)
- Francis Besset (francisbesset)
@@ -116,11 +116,11 @@ The Symfony Connect username in parenthesis allows to get more information
- John Wards (johnwards)
- Tomas Norkūnas (norkunas)
- Baptiste Clavié (talus)
+ - HypeMC (hypemc)
- Antoine Hérault (herzult)
- Paráda József (paradajozsef)
- Alexandre Daubois (alexandre-daubois)
- Vincent Langlet (deviling)
- - HypeMC (hypemc)
- Massimiliano Arione (garak)
- Arnaud Le Blanc (arnaud-lb)
- Przemysław Bogusz (przemyslaw-bogusz)
@@ -825,6 +825,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Rodrigo Borrego Bernabé (rodrigobb)
- Emanuele Iannone
- Jörn Lang (j.lang)
+ - Petr Duda (petrduda)
- Marcos Rezende (rezehnde)
- Denis Gorbachev (starfall)
- Peter van Dommelen
@@ -1350,7 +1351,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Simon Leblanc (leblanc_simon)
- Matthieu Mota (matthieumota)
- Mikhail Prosalov (mprosalov)
- - Petr Duda (petrduda)
- Ronny López (ronnylt)
- abdul malik ikhsan (samsonasik)
- Henry Snoek (snoek09)
diff --git a/composer.json b/composer.json
index dcb264728d6d6..2d72874a276a1 100644
--- a/composer.json
+++ b/composer.json
@@ -39,7 +39,7 @@
"doctrine/persistence": "^2",
"twig/twig": "^2.13|^3.0.4",
"psr/cache": "^1.0|^2.0",
- "psr/container": "^1.0",
+ "psr/container": "^1.1.1",
"psr/event-dispatcher": "^1.0",
"psr/link": "^1.0",
"psr/log": "^1|^2",
@@ -123,13 +123,12 @@
"async-aws/ses": "^1.0",
"async-aws/sqs": "^1.0",
"cache/integration-tests": "dev-master",
- "composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.12",
"doctrine/cache": "^1.6|^2.0",
"doctrine/collections": "~1.0",
"doctrine/data-fixtures": "^1.1",
"doctrine/dbal": "^2.10|^3.0",
- "doctrine/orm": "^2.7.3",
+ "doctrine/orm": "^2.7.4",
"guzzlehttp/promises": "^1.4",
"masterminds/html5": "^2.6",
"monolog/monolog": "^1.25.1|^2",
@@ -162,6 +161,12 @@
"ocramius/proxy-manager": "<2.1",
"phpunit/phpunit": "<5.4.3"
},
+ "config": {
+ "allow-plugins": {
+ "composer/package-versions-deprecated": true,
+ "symfony/runtime": true
+ }
+ },
"autoload": {
"psr-4": {
"Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/",
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index df9f82525162a..11b977b8461d3 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -18,6 +18,7 @@
+
diff --git a/psalm.xml b/psalm.xml
index 015c0ed18b21b..3fb94145699cf 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -27,5 +27,13 @@
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
index 324d5d26d4b06..3dc87f5af0a35 100644
--- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
+++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
@@ -75,7 +75,7 @@ public static function createChoiceLabel(object $choice): string
*/
public static function createChoiceName(object $choice, $key, string $value): string
{
- return str_replace('-', '_', (string) $value);
+ return str_replace('-', '_', $value);
}
/**
diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php
index 7a2ad9a8d9cd0..cd88bedca1e3b 100644
--- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php
+++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php
@@ -59,7 +59,7 @@ function (&$wrappedInstance, LazyLoadingInterface $manager) use ($name) {
$name = $this->aliases[$name];
}
if (isset($this->fileMap[$name])) {
- $wrappedInstance = $this->load($this->fileMap[$name]);
+ $wrappedInstance = $this->load($this->fileMap[$name], false);
} else {
$wrappedInstance = $this->{$this->methodMap[$name]}(false);
}
diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php
index c6b219aa795ab..30f12129c2719 100644
--- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php
+++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php
@@ -40,7 +40,7 @@ private function pingConnection(EntityManagerInterface $entityManager)
try {
$connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL());
- } catch (DBALException | Exception $e) {
+ } catch (DBALException|Exception $e) {
$connection->close();
$connection->connect();
}
diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
index 1484adf730efc..44c725ab4a9c3 100644
--- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
+++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
@@ -167,7 +167,6 @@ public function getTypes(string $class, string $property, array $context = [])
switch ($typeOfField) {
case Types::ARRAY:
case 'json_array':
- case 'json':
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
case Types::SIMPLE_ARRAY:
@@ -209,7 +208,7 @@ private function getMetadata(string $class): ?ClassMetadata
{
try {
return $this->entityManager ? $this->entityManager->getClassMetadata($class) : $this->classMetadataFactory->getMetadataFor($class);
- } catch (MappingException | OrmMappingException $exception) {
+ } catch (MappingException|OrmMappingException $exception) {
return null;
}
}
@@ -282,7 +281,6 @@ private function getPhpType(string $doctrineType): ?string
case Types::ARRAY:
case Types::SIMPLE_ARRAY:
case 'json_array':
- case 'json':
return Type::BUILTIN_TYPE_ARRAY;
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php
index d79b7d4998134..710e87a15e0b8 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php
@@ -15,6 +15,9 @@
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Doctrine\Logger\DbalLogger;
+/**
+ * @group legacy
+ */
class DbalLoggerTest extends TestCase
{
/**
@@ -46,8 +49,8 @@ public function getLogFixtures()
['SQL', null, []],
['SQL', [], []],
['SQL', ['foo' => 'bar'], ['foo' => 'bar']],
- ['SQL', ['foo' => "\x7F\xFF"], ['foo' => DbalLogger::BINARY_DATA_VALUE]],
- ['SQL', ['foo' => "bar\x7F\xFF"], ['foo' => DbalLogger::BINARY_DATA_VALUE]],
+ ['SQL', ['foo' => "\x7F\xFF"], ['foo' => '(binary value)']],
+ ['SQL', ['foo' => "bar\x7F\xFF"], ['foo' => '(binary value)']],
['SQL', ['foo' => ''], ['foo' => '']],
];
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php
index a004935a6afdc..dd7dabcc87db1 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php
@@ -12,8 +12,15 @@
namespace Symfony\Bridge\Doctrine\Tests;
use PHPUnit\Framework\TestCase;
+use ProxyManager\Proxy\LazyLoadingInterface;
+use ProxyManager\Proxy\ValueHolderInterface;
use Symfony\Bridge\Doctrine\ManagerRegistry;
+use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
use Symfony\Bridge\ProxyManager\Tests\LazyProxy\Dumper\PhpDumperTest;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
+use Symfony\Component\Filesystem\Filesystem;
class ManagerRegistryTest extends TestCase
{
@@ -39,6 +46,91 @@ public function testResetService()
$this->assertSame($foo, $container->get('foo'));
$this->assertObjectNotHasAttribute('bar', $foo);
}
+
+ /**
+ * When performing an entity manager lazy service reset, the reset operations may re-use the container
+ * to create a "fresh" service: when doing so, it can happen that the "fresh" service is itself a proxy.
+ *
+ * Because of that, the proxy will be populated with a wrapped value that is itself a proxy: repeating
+ * the reset operation keeps increasing this nesting until the application eventually runs into stack
+ * overflow or memory overflow operations, which can happen for long-running processes that rely on
+ * services that are reset very often.
+ */
+ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
+ {
+ // This test scenario only applies to containers composed as a set of generated sources
+ $this->dumpLazyServiceProjectAsFilesServiceContainer();
+
+ /** @var ContainerInterface $container */
+ $container = new \LazyServiceProjectAsFilesServiceContainer();
+
+ $registry = new TestManagerRegistry(
+ 'irrelevant',
+ [],
+ ['defaultManager' => 'foo'],
+ 'irrelevant',
+ 'defaultManager',
+ 'irrelevant'
+ );
+ $registry->setTestContainer($container);
+
+ $service = $container->get('foo');
+
+ self::assertInstanceOf(\stdClass::class, $service);
+ self::assertInstanceOf(LazyLoadingInterface::class, $service);
+ self::assertInstanceOf(ValueHolderInterface::class, $service);
+ self::assertFalse($service->isProxyInitialized());
+
+ $service->initializeProxy();
+
+ self::assertTrue($container->initialized('foo'));
+ self::assertTrue($service->isProxyInitialized());
+
+ $registry->resetManager();
+ $service->initializeProxy();
+
+ $wrappedValue = $service->getWrappedValueHolderValue();
+ self::assertInstanceOf(\stdClass::class, $wrappedValue);
+ self::assertNotInstanceOf(LazyLoadingInterface::class, $wrappedValue);
+ self::assertNotInstanceOf(ValueHolderInterface::class, $wrappedValue);
+ }
+
+ private function dumpLazyServiceProjectAsFilesServiceContainer()
+ {
+ if (class_exists(\LazyServiceProjectAsFilesServiceContainer::class, false)) {
+ return;
+ }
+
+ $container = new ContainerBuilder();
+
+ $container->register('foo', \stdClass::class)
+ ->setPublic(true)
+ ->setLazy(true);
+ $container->compile();
+
+ $fileSystem = new Filesystem();
+
+ $temporaryPath = $fileSystem->tempnam(sys_get_temp_dir(), 'symfonyManagerRegistryTest');
+ $fileSystem->remove($temporaryPath);
+ $fileSystem->mkdir($temporaryPath);
+
+ $dumper = new PhpDumper($container);
+
+ $dumper->setProxyDumper(new ProxyDumper());
+ $containerFiles = $dumper->dump([
+ 'class' => 'LazyServiceProjectAsFilesServiceContainer',
+ 'as_files' => true,
+ ]);
+
+ array_walk(
+ $containerFiles,
+ static function (string $containerSources, string $fileName) use ($temporaryPath): void {
+ (new Filesystem())->dumpFile($temporaryPath.'/'.$fileName, $containerSources);
+ }
+ );
+
+ require $temporaryPath.'/LazyServiceProjectAsFilesServiceContainer.php';
+ }
}
class TestManagerRegistry extends ManagerRegistry
diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php
index 3f0fb80ab04ce..3b9419d174a60 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php
@@ -207,7 +207,7 @@ public function typesProvider()
new Type(Type::BUILTIN_TYPE_INT),
new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
)]],
- ['json', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]],
+ ['json', null],
];
return $provider;
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
index ab35078f85fca..c1c698aea0ebd 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
@@ -37,6 +37,7 @@
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
+use Symfony\Component\Validator\Exception\UnexpectedValueException;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
/**
@@ -859,6 +860,32 @@ public function testValidateUniquenessWithEmptyIterator($entity, $result)
$this->assertNoViolation();
}
+ public function testValueMustBeObject()
+ {
+ $constraint = new UniqueEntity([
+ 'message' => 'myMessage',
+ 'fields' => ['name'],
+ 'em' => self::EM_NAME,
+ ]);
+
+ $this->expectException(UnexpectedValueException::class);
+
+ $this->validator->validate('foo', $constraint);
+ }
+
+ public function testValueCanBeNull()
+ {
+ $constraint = new UniqueEntity([
+ 'message' => 'myMessage',
+ 'fields' => ['name'],
+ 'em' => self::EM_NAME,
+ ]);
+
+ $this->validator->validate(null, $constraint);
+
+ $this->assertNoViolation();
+ }
+
public function resultWithEmptyIterator(): array
{
$entity = new SingleIntIdEntity(1, 'foo');
diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
index 4996848143b73..a34e7ef0a93a7 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
@@ -18,6 +18,7 @@
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
+use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* Unique Entity Validator checks if one or a set of fields contain unique values.
@@ -63,6 +64,10 @@ public function validate($entity, Constraint $constraint)
return;
}
+ if (!\is_object($entity)) {
+ throw new UnexpectedValueException($entity, 'object');
+ }
+
if ($constraint->em) {
$em = $this->registry->getManager($constraint->em);
diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
index f0f9a95652399..b3ab046ebd42b 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
@@ -49,7 +49,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
$className = $metadata->getClassName();
try {
$doctrineMetadata = $this->entityManager->getClassMetadata($className);
- } catch (MappingException | OrmMappingException $exception) {
+ } catch (MappingException|OrmMappingException $exception) {
return false;
}
diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json
index 49957bd989e7b..087ed34e7ad52 100644
--- a/src/Symfony/Bridge/Doctrine/composer.json
+++ b/src/Symfony/Bridge/Doctrine/composer.json
@@ -26,7 +26,6 @@
"symfony/service-contracts": "^1.1|^2"
},
"require-dev": {
- "composer/package-versions-deprecated": "^1.8",
"symfony/stopwatch": "^4.4|^5.0",
"symfony/cache": "^5.1",
"symfony/config": "^4.4|^5.0",
@@ -48,17 +47,19 @@
"doctrine/collections": "~1.0",
"doctrine/data-fixtures": "^1.1",
"doctrine/dbal": "^2.10|^3.0",
- "doctrine/orm": "^2.7.3"
+ "doctrine/orm": "^2.7.4"
},
"conflict": {
"doctrine/dbal": "<2.10",
- "doctrine/orm": "<2.7.3",
+ "doctrine/lexer": "<1.1",
+ "doctrine/orm": "<2.7.4",
"phpunit/phpunit": "<5.4.3",
"symfony/dependency-injection": "<4.4",
"symfony/form": "<5.1",
"symfony/http-kernel": "<5",
"symfony/messenger": "<4.4",
"symfony/property-info": "<5",
+ "symfony/proxy-manager-bridge": "<4.4.19",
"symfony/security-bundle": "<5",
"symfony/security-core": "<5.3",
"symfony/validator": "<5.2"
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php
index 99248c508ccab..4420ef3d0e46c 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php
@@ -107,7 +107,7 @@ private function __construct(array $thresholds = [], $regex = '', $verboseOutput
if (!isset($this->verboseOutput[$group])) {
throw new \InvalidArgumentException(sprintf('Unsupported verbosity group "%s", expected one of "%s".', $group, implode('", "', array_keys($this->verboseOutput))));
}
- $this->verboseOutput[$group] = (bool) $status;
+ $this->verboseOutput[$group] = $status;
}
if ($generateBaseline && !$baselineFile) {
diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json
index 91d93ba7cf421..403c522cd955d 100644
--- a/src/Symfony/Bridge/ProxyManager/composer.json
+++ b/src/Symfony/Bridge/ProxyManager/composer.json
@@ -17,7 +17,6 @@
],
"require": {
"php": ">=7.2.5",
- "composer/package-versions-deprecated": "^1.8",
"friendsofphp/proxy-manager-lts": "^1.0.2",
"symfony/dependency-injection": "^5.0",
"symfony/polyfill-php80": "^1.16"
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
index 2eb1bbce038c6..a0953a2d9f346 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
@@ -57,7 +57,7 @@ protected function setUp(): void
protected function renderForm(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = [])
@@ -66,42 +66,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = [])
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
index 6c84b32038b6e..b02d859f74856 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
@@ -107,7 +107,7 @@ public function testMoneyWidgetInIso()
protected function renderForm(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = [])
@@ -116,42 +116,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = [])
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php
index 5dbb7e5b6c8b8..33e1862afd74a 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php
@@ -59,7 +59,7 @@ protected function setUp(): void
protected function renderForm(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = [])
@@ -68,42 +68,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = [])
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php
index 285aa066e691d..41985a8ce2d85 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php
@@ -111,7 +111,7 @@ public function testMoneyWidgetInIso()
protected function renderForm(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = [])
@@ -120,42 +120,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = [])
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php
index 042cbf0e40a7e..ef924884a4751 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php
@@ -59,7 +59,7 @@ protected function setUp(): void
protected function renderForm(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = []): string
@@ -68,42 +68,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []):
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true): void
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php
index 1bf4a315fab0b..8c0e54744f964 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php
@@ -111,7 +111,7 @@ public function testMoneyWidgetInIso()
protected function renderForm(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = []): string
@@ -120,42 +120,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []):
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = []): string
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true): void
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
index 3190b4cb74bed..69f0c8f680933 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
@@ -331,7 +331,7 @@ public function testLabelHtmlIsTrue()
protected function renderForm(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = [])
@@ -340,42 +340,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = [])
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
index 48811750a82e0..b70a250e19639 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
@@ -217,7 +217,7 @@ public function testLabelHtmlIsTrue()
protected function renderForm(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form', $vars);
+ return $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = [])
@@ -226,42 +226,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = [])
$vars += ['label' => $label];
}
- return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderHelp(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'help');
+ return $this->renderer->searchAndRenderBlock($view, 'help');
}
protected function renderErrors(FormView $view)
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
+ return $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = [])
{
- return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
+ return $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = [])
{
- return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
+ return $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
diff --git a/src/Symfony/Bundle/DebugBundle/README.md b/src/Symfony/Bundle/DebugBundle/README.md
new file mode 100644
index 0000000000000..bed2f5b6d680a
--- /dev/null
+++ b/src/Symfony/Bundle/DebugBundle/README.md
@@ -0,0 +1,13 @@
+DebugBundle
+===========
+
+DebugBundle provides a tight integration of the Symfony VarDumper component and
+the ServerLogCommand from MonologBridge into the Symfony full-stack framework.
+
+Resources
+---------
+
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/src/Symfony/Bundle/DebugBundle/composer.json b/src/Symfony/Bundle/DebugBundle/composer.json
index 7c59e89ab3a55..e0b1e1052fb8b 100644
--- a/src/Symfony/Bundle/DebugBundle/composer.json
+++ b/src/Symfony/Bundle/DebugBundle/composer.json
@@ -1,7 +1,7 @@
{
"name": "symfony/debug-bundle",
"type": "symfony-bundle",
- "description": "Provides a tight integration of the Symfony Debug component into the Symfony full-stack framework",
+ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
index 137311bd6358d..2df5b72559c64 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
@@ -74,7 +74,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 1;
}
- $io->success('The container was lint successfully: all services are injected with values that are compatible with their type declarations.');
+ $io->success('The container was linted successfully: all services are injected with values that are compatible with their type declarations.');
return 0;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index a05a5ba06f7a2..5df7300ca3c62 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -1052,13 +1052,14 @@ private function addCacheSection(ArrayNodeDefinition $rootNode, callable $willBe
->prototype('array')
->fixXmlConfig('adapter')
->beforeNormalization()
- ->ifTrue(function ($v) { return (isset($v['adapters']) || \is_array($v['adapter'] ?? null)) && isset($v['provider']); })
- ->thenInvalid('Pool cannot have a "provider" while "adapter" is set to a map')
+ ->ifTrue(function ($v) { return isset($v['provider']) && \is_array($v['adapters'] ?? $v['adapter'] ?? null) && 1 < \count($v['adapters'] ?? $v['adapter']); })
+ ->thenInvalid('Pool cannot have a "provider" while more than one adapter is defined')
->end()
->children()
->arrayNode('adapters')
->performNoDeepMerging()
->info('One or more adapters to chain for creating the pool, defaults to "cache.app".')
+ ->beforeNormalization()->castToArray()->end()
->beforeNormalization()
->always()->then(function ($values) {
if ([0] === array_keys($values) && \is_array($values[0])) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index ac05cf1ad4c39..556232c88e26f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -2153,7 +2153,9 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
$pool['reset'] = 'reset';
}
- if ($isRedisTagAware) {
+ if ($isRedisTagAware && 'cache.app' === $name) {
+ $container->setAlias('cache.app.taggable', $name);
+ } elseif ($isRedisTagAware) {
$tagAwareId = $name;
$container->setAlias('.'.$name.'.inner', $name);
} elseif ($pool['tags']) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
index 7d4475a7e21ca..d288168d08d1a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
+++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
@@ -123,7 +123,10 @@ public function loginUser(object $user, string $firewallContext = 'main'): self
}
$token = new TestBrowserToken($user->getRoles(), $user, $firewallContext);
- $token->setAuthenticated(true);
+ // @deprecated since Symfony 5.4
+ if (method_exists($token, 'setAuthenticated')) {
+ $token->setAuthenticated(true, false);
+ }
$container = $this->getContainer();
$container->get('security.untracked_token_storage')->setToken($token);
@@ -139,8 +142,13 @@ public function loginUser(object $user, string $firewallContext = 'main'): self
$session->set('_security_'.$firewallContext, serialize($token));
$session->save();
- $cookie = new Cookie($session->getName(), $session->getId());
- $this->getCookieJar()->set($cookie);
+ $domains = array_unique(array_map(function (Cookie $cookie) use ($session) {
+ return $cookie->getName() === $session->getName() ? $cookie->getDomain() : '';
+ }, $this->getCookieJar()->all())) ?: [''];
+ foreach ($domains as $domain) {
+ $cookie = new Cookie($session->getName(), $session->getId(), null, null, $domain);
+ $this->getCookieJar()->set($cookie);
+ }
return $this;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
index 3fb6ce0a42d49..cdb205750f05d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Symfony\Component\Mailer\DataCollector\MessageDataCollector;
-use Symfony\Component\Mailer\EventListener\MessageLoggerListener;
return static function (ContainerConfigurator $container) {
$container->services()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
index c6353acdb75c7..c24738545d343 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
@@ -138,7 +138,12 @@ public function testForward()
public function testGetUser()
{
$user = new InMemoryUser('user', 'pass');
- $token = new UsernamePasswordToken($user, 'pass', 'default', ['ROLE_USER']);
+ if (method_exists(UsernamePasswordToken::class, 'setAuthenticated')) {
+ // @deprecated since Symfony 5.4
+ $token = new UsernamePasswordToken($user, 'pass', 'default', ['ROLE_USER']);
+ } else {
+ $token = new UsernamePasswordToken($user, 'default', ['ROLE_USER']);
+ }
$controller = $this->createController();
$controller->setContainer($this->getContainerWithTokenStorage($token));
@@ -148,6 +153,11 @@ public function testGetUser()
public function testGetUserAnonymousUserConvertedToNull()
{
+ // @deprecated since Symfony 5.4
+ if (!class_exists(AnonymousToken::class)) {
+ $this->markTestSkipped('This test requires "symfony/security-core" <6.0.');
+ }
+
$token = new AnonymousToken('default', 'anon.');
$controller = $this->createController();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache_app_redis_tag_aware.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache_app_redis_tag_aware.php
new file mode 100644
index 0000000000000..44855c62adbf1
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache_app_redis_tag_aware.php
@@ -0,0 +1,7 @@
+loadFromExtension('framework', [
+ 'cache' => [
+ 'app' => 'cache.adapter.redis_tag_aware',
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache_app_redis_tag_aware_pool.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache_app_redis_tag_aware_pool.php
new file mode 100644
index 0000000000000..bf3ee2de2b357
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache_app_redis_tag_aware_pool.php
@@ -0,0 +1,12 @@
+loadFromExtension('framework', [
+ 'cache' => [
+ 'app' => 'cache.redis_tag_aware.foo',
+ 'pools' => [
+ 'cache.redis_tag_aware.foo' => [
+ 'adapter' => 'cache.adapter.redis_tag_aware',
+ ],
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache_app_redis_tag_aware.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache_app_redis_tag_aware.xml
new file mode 100644
index 0000000000000..2929e87e200e8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache_app_redis_tag_aware.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ cache.adapter.redis_tag_aware
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache_app_redis_tag_aware_pool.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache_app_redis_tag_aware_pool.xml
new file mode 100644
index 0000000000000..65c06a1da6df7
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache_app_redis_tag_aware_pool.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ cache.redis_tag_aware.foo
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache_app_redis_tag_aware.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache_app_redis_tag_aware.yml
new file mode 100644
index 0000000000000..b1c89adafa0ca
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache_app_redis_tag_aware.yml
@@ -0,0 +1,3 @@
+framework:
+ cache:
+ app: cache.adapter.redis_tag_aware
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache_app_redis_tag_aware_pool.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache_app_redis_tag_aware_pool.yml
new file mode 100644
index 0000000000000..9eb8b83c775c5
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache_app_redis_tag_aware_pool.yml
@@ -0,0 +1,6 @@
+framework:
+ cache:
+ app: cache.redis_tag_aware.foo
+ pools:
+ cache.redis_tag_aware.foo:
+ adapter: cache.adapter.redis_tag_aware
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index e6135d93ca320..b13e6a5c3c0e8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -1587,6 +1587,32 @@ public function testRedisTagAwareAdapter()
}
}
+ /**
+ * @dataProvider appRedisTagAwareConfigProvider
+ */
+ public function testAppRedisTagAwareAdapter(string $configFile)
+ {
+ $container = $this->createContainerFromFile($configFile);
+
+ foreach ([TagAwareCacheInterface::class, CacheInterface::class, CacheItemPoolInterface::class] as $alias) {
+ $def = $container->findDefinition($alias);
+
+ while ($def instanceof ChildDefinition) {
+ $def = $container->getDefinition($def->getParent());
+ }
+
+ $this->assertSame(RedisTagAwareAdapter::class, $def->getClass());
+ }
+ }
+
+ public function appRedisTagAwareConfigProvider(): array
+ {
+ return [
+ ['cache_app_redis_tag_aware'],
+ ['cache_app_redis_tag_aware_pool'],
+ ];
+ }
+
public function testRemovesResourceCheckerConfigCacheFactoryArgumentOnlyIfNoDebug()
{
$container = $this->createContainer(['kernel.debug' => true]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SecurityTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SecurityTest.php
index a53513baea254..d97039562119c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SecurityTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SecurityTest.php
@@ -70,4 +70,20 @@ public function testLoginInBetweenRequests()
$client->request('GET', '/main/user_profile');
$this->assertEquals('Welcome the-username!', $client->getResponse()->getContent());
}
+
+ public function testLoginUserMultipleTimes()
+ {
+ $userFoo = new InMemoryUser('the-username', 'the-password', ['ROLE_FOO']);
+ $userBar = new InMemoryUser('no-role-username', 'the-password');
+ $client = $this->createClient(['test_case' => 'Security', 'root_config' => 'config.yml']);
+ $client->loginUser($userFoo);
+
+ $client->request('GET', '/main/user_profile');
+ $this->assertEquals('Welcome the-username!', $client->getResponse()->getContent());
+
+ $client->loginUser($userBar);
+
+ $client->request('GET', '/main/user_profile');
+ $this->assertEquals('Welcome no-role-username!', $client->getResponse()->getContent());
+ }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
index 557134a392dfe..77a897fc193c7 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
@@ -1027,7 +1027,7 @@ private function createExpression(ContainerBuilder $container, string $expressio
private function createRequestMatcher(ContainerBuilder $container, string $path = null, string $host = null, int $port = null, array $methods = [], array $ips = null, array $attributes = []): Reference
{
if ($methods) {
- $methods = array_map('strtoupper', (array) $methods);
+ $methods = array_map('strtoupper', $methods);
}
if (null !== $ips) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
index 3110b1ca38c97..dd2de44bc350f 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
@@ -16,7 +16,6 @@
use Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
index efba9eb54a799..037bbcad5a1ab 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
@@ -74,7 +74,7 @@ static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime)
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
- } elseif (0 === $item->expiry) {
+ } elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
index fd5268ce81aa0..7ac4c42cd6fa1 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
@@ -79,7 +79,7 @@ static function ($deferred, &$expiredIds, $getId, $tagPrefix, $defaultLifetime)
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
- } elseif (0 === $item->expiry) {
+ } elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
diff --git a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
index 6fda0ef37f262..5fc8f6295b30c 100644
--- a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
@@ -60,7 +60,14 @@ protected function doFetch(array $ids)
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
$values = [];
- foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) {
+ $ids = array_flip($ids);
+ foreach (apcu_fetch(array_keys($ids), $ok) ?: [] as $k => $v) {
+ if (!isset($ids[$k])) {
+ // work around https://github.com/krakjoe/apcu/issues/247
+ $k = key($ids);
+ }
+ unset($ids[$k]);
+
if (null !== $v || $ok) {
$values[$k] = null !== $this->marshaller ? $this->marshaller->unmarshall($v) : $v;
}
diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
index 0fa78d07c14a9..bd5ec9ec9884b 100644
--- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
@@ -190,14 +190,14 @@ public function save(CacheItemInterface $item)
$now = microtime(true);
- if (0 === $expiry) {
- $expiry = \PHP_INT_MAX;
- }
-
- if (null !== $expiry && $expiry <= $now) {
- $this->deleteItem($key);
+ if (null !== $expiry) {
+ if (!$expiry) {
+ $expiry = \PHP_INT_MAX;
+ } elseif ($expiry <= $now) {
+ $this->deleteItem($key);
- return true;
+ return true;
+ }
}
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
index 7a47e589e0063..1b38f2fd9c1a7 100644
--- a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
@@ -437,7 +437,7 @@ protected function doSave(array $values, int $lifetime)
if (null === $driver && !(\is_object($result) ? $result->rowCount() : $stmt->rowCount())) {
try {
$insertStmt->execute();
- } catch (DBALException | Exception $e) {
+ } catch (DBALException|Exception $e) {
} catch (\PDOException $e) {
// A concurrent write won, let it be
}
diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
index 7291a7e48f6e0..c715cade5c1f0 100644
--- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
@@ -92,7 +92,7 @@ static function (CacheItemInterface $innerItem, array $item) {
$item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
}
$innerItem->set($item["\0*\0value"]);
- $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null);
+ $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
},
null,
CacheItem::class
diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php
index ecedac8c07e87..4190a79ea71fe 100644
--- a/src/Symfony/Component/Cache/LockRegistry.php
+++ b/src/Symfony/Component/Cache/LockRegistry.php
@@ -89,7 +89,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
$key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1;
- if ($key < 0 || (self::$lockedFiles[$key] ?? false) || !$lock = self::open($key)) {
+ if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) {
return $callback($item, $save);
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
index b67fb5cd0cc79..36d487fe14105 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
@@ -128,7 +128,7 @@ public function testGetMetadata()
$metadata = $item->getMetadata();
$this->assertArrayHasKey(CacheItem::METADATA_CTIME, $metadata);
- $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 10);
+ $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 150);
$this->assertArrayHasKey(CacheItem::METADATA_EXPIRY, $metadata);
$this->assertEqualsWithDelta(9 + time(), $metadata[CacheItem::METADATA_EXPIRY], 1);
}
@@ -306,6 +306,15 @@ public function testWeirdDataMatchingMetadataWrappedValues()
$this->assertTrue($cache->hasItem('foobar'));
}
+
+ public function testNullByteInKey()
+ {
+ $cache = $this->createCachePool(0, __FUNCTION__);
+
+ $cache->save($cache->getItem("a\0b")->set(123));
+
+ $this->assertSame(123, $cache->getItem("a\0b")->get());
+ }
}
class NotUnserializable
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
new file mode 100644
index 0000000000000..46516e0095e6e
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Adapter;
+
+use Psr\Cache\CacheItemPoolInterface;
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
+use Symfony\Component\Cache\Adapter\ProxyAdapter;
+use Symfony\Component\Cache\Adapter\RedisAdapter;
+use Symfony\Component\Cache\CacheItem;
+
+/**
+ * @group integration
+ */
+class ProxyAdapterAndRedisAdapterTest extends AbstractRedisAdapterTest
+{
+ protected $skippedTests = [
+ 'testPrune' => 'RedisAdapter does not implement PruneableInterface.',
+ ];
+
+ public static function setUpBeforeClass(): void
+ {
+ parent::setUpBeforeClass();
+ self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
+ }
+
+ public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ {
+ return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime);
+ }
+
+ public function testSaveItemPermanently()
+ {
+ $setCacheItemExpiry = \Closure::bind(
+ static function (CacheItem $item, $expiry) {
+ $item->expiry = $expiry;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+
+ $cache = $this->createCachePool(1);
+ $value = rand();
+ $item = $cache->getItem('foo');
+ $setCacheItemExpiry($item, 0);
+ $cache->save($item->set($value));
+ $item = $cache->getItem('bar');
+ $setCacheItemExpiry($item, 0.0);
+ $cache->save($item->set($value));
+ $item = $cache->getItem('baz');
+ $cache->save($item->set($value));
+
+ $this->assertSame($value, $this->cache->getItem('foo')->get());
+ $this->assertSame($value, $this->cache->getItem('bar')->get());
+ $this->assertSame($value, $this->cache->getItem('baz')->get());
+
+ sleep(1);
+ $this->assertSame($value, $this->cache->getItem('foo')->get());
+ $this->assertSame($value, $this->cache->getItem('bar')->get());
+ $this->assertFalse($this->cache->getItem('baz')->isHit());
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
index 7e69001648fcc..99e044f824f3f 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
@@ -14,12 +14,10 @@
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
-use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
-use Symfony\Component\Cache\LockRegistry;
use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter;
use Symfony\Component\Filesystem\Filesystem;
@@ -199,24 +197,6 @@ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags
$this->assertFalse($item->isHit());
}
- public function testLog()
- {
- $lockFiles = LockRegistry::setFiles([__FILE__]);
-
- $logger = $this->createMock(LoggerInterface::class);
- $logger
- ->expects($this->atLeastOnce())
- ->method($this->anything());
-
- $cache = new TagAwareAdapter(new ArrayAdapter());
- $cache->setLogger($logger);
-
- // Computing will produce at least one log
- $cache->get('foo', static function (): string { return 'ccc'; });
-
- LockRegistry::setFiles($lockFiles);
- }
-
/**
* @return MockObject&PruneableCacheInterface
*/
diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
index 2f5af04b075cc..9a491adb5acb8 100644
--- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php
+++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
@@ -31,7 +31,7 @@ trait ContractsTrait
doGet as private contractsGet;
}
- private $callbackWrapper = [LockRegistry::class, 'compute'];
+ private $callbackWrapper;
private $computing = [];
/**
@@ -41,8 +41,16 @@ trait ContractsTrait
*/
public function setCallbackWrapper(?callable $callbackWrapper): callable
{
+ if (!isset($this->callbackWrapper)) {
+ $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']);
+
+ if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
+ $this->setCallbackWrapper(null);
+ }
+ }
+
$previousWrapper = $this->callbackWrapper;
- $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
+ $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
return $callback($item, $save);
};
@@ -82,6 +90,10 @@ static function (CacheItem $item, float $startTime, ?array &$metadata) {
$this->computing[$key] = $key;
$startTime = microtime(true);
+ if (!isset($this->callbackWrapper)) {
+ $this->setCallbackWrapper($this->setCallbackWrapper(null));
+ }
+
try {
$value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$setMetadata($item, $startTime, $metadata);
diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
index 3acb6d01de283..67d2b945e5fb6 100644
--- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
+++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
@@ -38,7 +38,7 @@ public function __construct(string $resource, bool $exists = null)
{
$this->resource = $resource;
if (null !== $exists) {
- $this->exists = [(bool) $exists, null];
+ $this->exists = [$exists, null];
}
}
diff --git a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
index c845c76ed3ced..c622d606bc303 100644
--- a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
+++ b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
@@ -169,6 +169,8 @@ public function getDataForPhpize(): array
[1, '1'],
[-1, '-1'],
[0777, '0777'],
+ [-511, '-0777'],
+ ['0877', '0877'],
[255, '0xFF'],
[100.0, '1e2'],
[-120.0, '-1.2E2'],
diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php
index 196d44f07edce..8258a0627a571 100644
--- a/src/Symfony/Component/Config/Util/XmlUtils.php
+++ b/src/Symfony/Component/Config/Util/XmlUtils.php
@@ -236,15 +236,11 @@ public static function phpize($value)
case 'null' === $lowercaseValue:
return null;
case ctype_digit($value):
- $raw = $value;
- $cast = (int) $value;
-
- return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)):
$raw = $value;
$cast = (int) $value;
- return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
+ return self::isOctal($value) ? \intval($value, 8) : (($raw === (string) $cast) ? $cast : $raw);
case 'true' === $lowercaseValue:
return true;
case 'false' === $lowercaseValue:
@@ -281,4 +277,13 @@ protected static function getXmlErrors(bool $internalErrors)
return $errors;
}
+
+ private static function isOctal(string $str): bool
+ {
+ if ('-' === $str[0]) {
+ $str = substr($str, 1);
+ }
+
+ return $str === '0'.decoct(\intval($str, 8));
+ }
}
diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php
index f82c16bae84a0..f114dbe7c20f7 100644
--- a/src/Symfony/Component/Console/Helper/ProcessHelper.php
+++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php
@@ -92,9 +92,9 @@ public function run(OutputInterface $output, $cmd, string $error = null, callabl
* This is identical to run() except that an exception is thrown if the process
* exits with a non-zero exit code.
*
- * @param string|Process $cmd An instance of Process or a command to run
- * @param callable|null $callback A PHP callback to run whenever there is some
- * output available on STDOUT or STDERR
+ * @param array|Process $cmd An instance of Process or a command to run
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
*
* @return Process The process that ran
*
diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php
index 04d2d411d6e5a..553be3404e03e 100644
--- a/src/Symfony/Component/Console/Question/Question.php
+++ b/src/Symfony/Component/Console/Question/Question.php
@@ -105,7 +105,7 @@ public function setHidden(bool $hidden)
throw new LogicException('A hidden question cannot use the autocompleter.');
}
- $this->hidden = (bool) $hidden;
+ $this->hidden = $hidden;
return $this;
}
@@ -127,7 +127,7 @@ public function isHiddenFallback()
*/
public function setHiddenFallback(bool $fallback)
{
- $this->hiddenFallback = (bool) $fallback;
+ $this->hiddenFallback = $fallback;
return $this;
}
@@ -230,11 +230,8 @@ public function getValidator()
*/
public function setMaxAttempts(?int $attempts)
{
- if (null !== $attempts) {
- $attempts = (int) $attempts;
- if ($attempts < 1) {
- throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
- }
+ if (null !== $attempts && $attempts < 1) {
+ throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
}
$this->attempts = $attempts;
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index 4ff93b1cc29c6..5421305693149 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -883,6 +883,9 @@ public function testRenderExceptionLineBreaks()
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks');
}
+ /**
+ * @group transient-on-windows
+ */
public function testRenderAnonymousException()
{
$application = new Application();
@@ -906,6 +909,9 @@ public function testRenderAnonymousException()
$this->assertStringContainsString('Dummy type "class@anonymous" is invalid.', $tester->getDisplay(true));
}
+ /**
+ * @group transient-on-windows
+ */
public function testRenderExceptionStackTraceContainsRootException()
{
$application = new Application();
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
index 4881e4fe10320..97dc4b094ac31 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
+use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\LogicException;
@@ -128,25 +129,35 @@ protected function getConstructor(Definition $definition, bool $required)
if ($factory) {
[$class, $method] = $factory;
+
+ if ('__construct' === $method) {
+ throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
+ }
+
if ($class instanceof Reference) {
- $class = $this->container->findDefinition((string) $class)->getClass();
+ $factoryDefinition = $this->container->findDefinition((string) $class);
+ while ((null === $class = $factoryDefinition->getClass()) && $factoryDefinition instanceof ChildDefinition) {
+ $factoryDefinition = $this->container->findDefinition($factoryDefinition->getParent());
+ }
} elseif ($class instanceof Definition) {
$class = $class->getClass();
} elseif (null === $class) {
$class = $definition->getClass();
}
- if ('__construct' === $method) {
- throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
- }
-
return $this->getReflectionMethod(new Definition($class), $method);
}
- $class = $definition->getClass();
+ while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) {
+ $definition = $this->container->findDefinition($definition->getParent());
+ }
try {
if (!$r = $this->container->getReflectionClass($class)) {
+ if (null === $class) {
+ throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId));
+ }
+
throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
}
} catch (\ReflectionException $e) {
@@ -174,7 +185,11 @@ protected function getReflectionMethod(Definition $definition, string $method)
return $this->getConstructor($definition, true);
}
- if (!$class = $definition->getClass()) {
+ while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) {
+ $definition = $this->container->findDefinition($definition->getParent());
+ }
+
+ if (null === $class) {
throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId));
}
@@ -183,6 +198,10 @@ protected function getReflectionMethod(Definition $definition, string $method)
}
if (!$r->hasMethod($method)) {
+ if ($r->hasMethod('__call') && ($r = $r->getMethod('__call')) && $r->isPublic()) {
+ return new \ReflectionMethod(static function (...$arguments) {}, '__invoke');
+ }
+
throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
index d6db29235ef0c..c71ea503bfc0b 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
@@ -134,6 +134,11 @@ protected function processValue($value, bool $isRoot = false)
continue;
}
+ if (is_subclass_of($m[1], \UnitEnum::class)) {
+ $bindingNames[substr($key, \strlen($m[0]))] = $binding;
+ continue;
+ }
+
if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) {
throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, get_debug_type($bindingValue)));
}
diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php
index 90f8f886cd942..9d711f8982f46 100644
--- a/src/Symfony/Component/DependencyInjection/Definition.php
+++ b/src/Symfony/Component/DependencyInjection/Definition.php
@@ -146,7 +146,7 @@ public function setDecoratedService(?string $id, string $renamedId = null, int $
if (null === $id) {
$this->decoratedService = null;
} else {
- $this->decoratedService = [$id, $renamedId, (int) $priority];
+ $this->decoratedService = [$id, $renamedId, $priority];
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
$this->decoratedService[] = $invalidBehavior;
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
index a04f75a7fd041..2281e02701989 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
@@ -143,7 +143,7 @@ private function addService(Definition $definition, ?string $id, \DOMElement $pa
$tag->appendChild($this->document->createTextNode($name));
}
foreach ($attributes as $key => $value) {
- $tag->setAttribute($key, $value);
+ $tag->setAttribute($key, $value ?? '');
}
$service->appendChild($tag);
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
index 50e8b13839b09..76b6b0fac410b 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
@@ -135,7 +135,7 @@ private function executeCallback(callable $callback, ContainerConfigurator $cont
default:
try {
$configBuilder = $this->configBuilder($type);
- } catch (InvalidArgumentException | \LogicException $e) {
+ } catch (InvalidArgumentException|\LogicException $e) {
throw new \InvalidArgumentException(sprintf('Could not resolve argument "%s" for "%s".', $type.' $'.$parameter->getName(), $path), 0, $e);
}
$configBuilders[] = $configBuilder;
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index f8375d9acd56d..13b80a44bfabd 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -212,7 +212,7 @@ private function parseDefinition(\DOMElement $service, string $file, Definition
if ($alias = $service->getAttribute('alias')) {
$this->validateAlias($service, $file);
- $this->container->setAlias((string) $service->getAttribute('id'), $alias = new Alias($alias));
+ $this->container->setAlias($service->getAttribute('id'), $alias = new Alias($alias));
if ($publicAttr = $service->getAttribute('public')) {
$alias->setPublic(XmlUtils::phpize($publicAttr));
} elseif ($defaults->getChanges()['public'] ?? false) {
@@ -350,7 +350,7 @@ private function parseDefinition(\DOMElement $service, string $file, Definition
}
if ('' === $tagName && '' === $tagName = $tag->getAttribute('name')) {
- throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', (string) $service->getAttribute('id'), $file));
+ throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', $service->getAttribute('id'), $file));
}
$definition->addTag($tagName, $parameters);
@@ -380,7 +380,7 @@ private function parseDefinition(\DOMElement $service, string $file, Definition
} elseif ('null' === $decorationOnInvalid) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
} else {
- throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, (string) $service->getAttribute('id'), $file));
+ throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, $service->getAttribute('id'), $file));
}
$renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php
index fad04fc6df08f..41da2c7267a40 100644
--- a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php
+++ b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php
@@ -109,7 +109,7 @@ public function set(string $name, $value)
*/
public function has(string $name)
{
- return \array_key_exists((string) $name, $this->parameters);
+ return \array_key_exists($name, $this->parameters);
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php
new file mode 100644
index 0000000000000..aecdc9a5a2169
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php
@@ -0,0 +1,127 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Tests\Compiler;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\ChildDefinition;
+use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy;
+
+class AbstractRecursivePassTest extends TestCase
+{
+ public function testGetConstructorResolvesFactoryChildDefinitionsClass()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('factory_dummy_class', FactoryDummy::class);
+ $container
+ ->register('parent', '%factory_dummy_class%')
+ ->setAbstract(true);
+ $container->setDefinition('child', new ChildDefinition('parent'));
+ $container
+ ->register('foo', \stdClass::class)
+ ->setFactory([new Reference('child'), 'createFactory']);
+
+ $pass = new class() extends AbstractRecursivePass {
+ public $actual;
+
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->actual = $this->getConstructor($value, true);
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ };
+ $pass->process($container);
+
+ $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual);
+ $this->assertSame(FactoryDummy::class, $pass->actual->class);
+ }
+
+ public function testGetConstructorResolvesChildDefinitionsClass()
+ {
+ $container = new ContainerBuilder();
+ $container
+ ->register('parent', Bar::class)
+ ->setAbstract(true);
+ $container->setDefinition('foo', new ChildDefinition('parent'));
+
+ $pass = new class() extends AbstractRecursivePass {
+ public $actual;
+
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->actual = $this->getConstructor($value, true);
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ };
+ $pass->process($container);
+
+ $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual);
+ $this->assertSame(Bar::class, $pass->actual->class);
+ }
+
+ public function testGetReflectionMethodResolvesChildDefinitionsClass()
+ {
+ $container = new ContainerBuilder();
+ $container
+ ->register('parent', Bar::class)
+ ->setAbstract(true);
+ $container->setDefinition('foo', new ChildDefinition('parent'));
+
+ $pass = new class() extends AbstractRecursivePass {
+ public $actual;
+
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->actual = $this->getReflectionMethod($value, 'create');
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ };
+ $pass->process($container);
+
+ $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual);
+ $this->assertSame(Bar::class, $pass->actual->class);
+ }
+
+ public function testGetConstructorDefinitionNoClass()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Invalid service "foo": the class is not set.');
+
+ $container = new ContainerBuilder();
+ $container->register('foo');
+
+ (new class() extends AbstractRecursivePass {
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->getConstructor($value, true);
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ })->process($container);
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
index 8c15ebfa10487..38538f27b0f9f 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
@@ -985,4 +985,22 @@ public function testIntersectionTypeFailsWithReference()
(new CheckTypeDeclarationsPass(true))->process($container);
}
+
+ public function testCallableClass()
+ {
+ $container = new ContainerBuilder();
+ $definition = $container->register('foo', CallableClass::class);
+ $definition->addMethodCall('callMethod', [123]);
+
+ (new CheckTypeDeclarationsPass())->process($container);
+
+ $this->addToAssertionCount(1);
+ }
+}
+
+class CallableClass
+{
+ public function __call($name, $arguments)
+ {
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
index 2e5016c623f4d..3ddad62d0e5d7 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
@@ -25,7 +25,9 @@
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedEnumArgumentDummy;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
use Symfony\Component\DependencyInjection\Tests\Fixtures\WithTarget;
use Symfony\Component\DependencyInjection\TypedReference;
@@ -65,6 +67,27 @@ public function testProcess()
$this->assertEquals([['setSensitiveClass', [new Reference('foo')]]], $definition->getMethodCalls());
}
+ /**
+ * @requires PHP 8.1
+ */
+ public function testProcessEnum()
+ {
+ $container = new ContainerBuilder();
+
+ $bindings = [
+ FooUnitEnum::class.' $bar' => new BoundArgument(FooUnitEnum::BAR),
+ ];
+
+ $definition = $container->register(NamedEnumArgumentDummy::class, NamedEnumArgumentDummy::class);
+ $definition->setBindings($bindings);
+
+ $pass = new ResolveBindingsPass();
+ $pass->process($container);
+
+ $expected = [FooUnitEnum::BAR];
+ $this->assertEquals($expected, $definition->getArguments());
+ }
+
public function testUnusedBinding()
{
$this->expectException(InvalidArgumentException::class);
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php
new file mode 100644
index 0000000000000..c172c996a7fb7
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
+
+class NamedEnumArgumentDummy
+{
+ public function __construct(FooUnitEnum $bar)
+ {
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php
index 021b921ec208e..47922be9bde58 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php
@@ -17,6 +17,7 @@
->register('foo', FooClass::class)
->addTag('foo', ['foo' => 'foo'])
->addTag('foo', ['bar' => 'bar', 'baz' => 'baz'])
+ ->addTag('nullable', ['bar' => 'bar', 'baz' => null])
->addTag('foo', ['name' => 'bar', 'baz' => 'baz'])
->setFactory(['Bar\\FooClass', 'getInstance'])
->setArguments(['foo', new Reference('foo.baz'), ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%'], true, new Reference('service_container')])
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml
index ecae10e4051cc..a52d82ac1a3ab 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml
@@ -11,6 +11,7 @@
foo
+
foo
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml
index b202a8d7f681f..a5a10a5a87c43 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml
@@ -14,6 +14,7 @@ services:
- foo: { foo: foo }
- foo: { bar: bar, baz: baz }
- foo: { name: bar, baz: baz }
+ - nullable: { bar: bar, baz: ~ }
arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', foobar: '%foo%' }, true, '@service_container']
properties: { foo: bar, moo: '@foo.baz', qux: { '%foo%': 'foo is %foo%', foobar: '%foo%' } }
calls:
diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php
index 19ead5213a37a..d2993e98c25ac 100644
--- a/src/Symfony/Component/DomCrawler/Crawler.php
+++ b/src/Symfony/Component/DomCrawler/Crawler.php
@@ -1146,7 +1146,7 @@ protected function sibling(\DOMNode $node, string $siblingDir = 'nextSibling')
private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument
{
- return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset), [], $charset);
+ return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset));
}
private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument
@@ -1182,11 +1182,11 @@ private function convertToHtmlEntities(string $htmlContent, string $charset = 'U
try {
return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset);
- } catch (\Exception | \ValueError $e) {
+ } catch (\Exception|\ValueError $e) {
try {
$htmlContent = iconv($charset, 'UTF-8', $htmlContent);
$htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8');
- } catch (\Exception | \ValueError $e) {
+ } catch (\Exception|\ValueError $e) {
}
return $htmlContent;
diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php
index 4d2cf32ed3dfb..3db6be3002400 100644
--- a/src/Symfony/Component/Dotenv/Dotenv.php
+++ b/src/Symfony/Component/Dotenv/Dotenv.php
@@ -81,8 +81,8 @@ public function usePutenv(bool $usePutenv = true): self
/**
* Loads one or several .env files.
*
- * @param string $path A file to load
- * @param ...string $extraPaths A list of additional files to load
+ * @param string $path A file to load
+ * @param string[] ...$extraPaths A list of additional files to load
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
@@ -167,8 +167,8 @@ public function bootEnv(string $path, string $defaultEnv = 'dev', array $testEnv
/**
* Loads one or several .env files and enables override existing vars.
*
- * @param string $path A file to load
- * @param ...string $extraPaths A list of additional files to load
+ * @param string $path A file to load
+ * @param string[] ...$extraPaths A list of additional files to load
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php
index 1abafc15289f9..ffb823eed23c2 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php
@@ -111,7 +111,7 @@ class ErrorHandler
public static function register(self $handler = null, bool $replace = true): self
{
if (null === self::$reservedMemory) {
- self::$reservedMemory = str_repeat('x', 10240);
+ self::$reservedMemory = str_repeat('x', 32768);
register_shutdown_function(__CLASS__.'::handleFatalError');
}
@@ -348,7 +348,7 @@ public function scopeAt(int $levels, bool $replace = false): int
public function traceAt(int $levels, bool $replace = false): int
{
$prev = $this->tracedErrors;
- $this->tracedErrors = (int) $levels;
+ $this->tracedErrors = $levels;
if (!$replace) {
$this->tracedErrors |= $prev;
}
@@ -615,7 +615,9 @@ public function handleException(\Throwable $exception)
}
$loggedErrors = $this->loggedErrors;
- $this->loggedErrors = $exception === $handlerException ? 0 : $this->loggedErrors;
+ if ($exception === $handlerException) {
+ $this->loggedErrors &= ~$type;
+ }
try {
$this->handleException($handlerException);
diff --git a/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
index 71ce257a76782..09356cda50a5b 100644
--- a/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
+++ b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
@@ -298,7 +298,6 @@ public function setTraceFromThrowable(\Throwable $throwable): self
}
/**
- *
* @return $this
*/
public function setTrace(array $trace, ?string $file, ?int $line): self
diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt
index 06540f4530121..be5ce6a5cdffa 100644
--- a/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt
+++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt
@@ -16,7 +16,9 @@ if (true) {
{
public function log($level, $message, array $context = []): void
{
- echo 'LOG: ', $message, "\n";
+ if (0 !== strpos($message, 'Deprecated: ')) {
+ echo 'LOG: ', $message, "\n";
+ }
}
}
}
@@ -34,5 +36,5 @@ Exception {%S
#message: "foo"
#code: 0
#file: "%s"
- #line: 25
+ #line: 27
}
diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
index a18e6185beeec..8508ab707b9a3 100644
--- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
+++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
@@ -64,7 +64,7 @@ public function current()
// the logic here avoids redoing the same work in all iterations
if (null === $subPathname = $this->subPath) {
- $subPathname = $this->subPath = (string) $this->getSubPath();
+ $subPathname = $this->subPath = $this->getSubPath();
}
if ('' !== $subPathname) {
$subPathname .= $this->directorySeparator;
diff --git a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
index 037810aea799f..f48cc941f8ad3 100644
--- a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
+++ b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
@@ -21,7 +21,7 @@ class RecursiveDirectoryIteratorTest extends IteratorTestCase
public function testRewindOnFtp()
{
try {
- $i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
+ $i = new RecursiveDirectoryIterator('ftp://speedtest:speedtest@ftp.otenet.gr/', \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped('Unsupported stream "ftp".');
}
@@ -37,14 +37,14 @@ public function testRewindOnFtp()
public function testSeekOnFtp()
{
try {
- $i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
+ $i = new RecursiveDirectoryIterator('ftp://speedtest:speedtest@ftp.otenet.gr/', \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped('Unsupported stream "ftp".');
}
$contains = [
- 'ftp://speedtest.tele2.net'.\DIRECTORY_SEPARATOR.'1000GB.zip',
- 'ftp://speedtest.tele2.net'.\DIRECTORY_SEPARATOR.'100GB.zip',
+ 'ftp://speedtest:speedtest@ftp.otenet.gr'.\DIRECTORY_SEPARATOR.'test100Mb.db',
+ 'ftp://speedtest:speedtest@ftp.otenet.gr'.\DIRECTORY_SEPARATOR.'test100k.db',
];
$actual = [];
diff --git a/src/Symfony/Component/Form/AbstractRendererEngine.php b/src/Symfony/Component/Form/AbstractRendererEngine.php
index b4437471234a3..33e66f84fc62c 100644
--- a/src/Symfony/Component/Form/AbstractRendererEngine.php
+++ b/src/Symfony/Component/Form/AbstractRendererEngine.php
@@ -68,7 +68,7 @@ public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true)
// Do not cast, as casting turns objects into arrays of properties
$this->themes[$cacheKey] = \is_array($themes) ? $themes : [$themes];
- $this->useDefaultThemes[$cacheKey] = (bool) $useDefaultThemes;
+ $this->useDefaultThemes[$cacheKey] = $useDefaultThemes;
// Unset instead of resetting to an empty array, in order to allow
// implementations (like TwigRendererEngine) to check whether $cacheKey
diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php
index 959f6bcf782a8..b3185d1a376c6 100644
--- a/src/Symfony/Component/Form/FormFactory.php
+++ b/src/Symfony/Component/Form/FormFactory.php
@@ -66,7 +66,7 @@ public function createNamedBuilder(string $name, string $type = FormType::class,
$type = $this->registry->getType($type);
- $builder = $type->createBuilder($this, (string) $name, $options);
+ $builder = $type->createBuilder($this, $name, $options);
// Explicitly call buildForm() in order to be able to override either
// createBuilder() or buildForm() in the resolved form type
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
index 4ed719917549d..4a98eea8eb314 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
@@ -24,7 +24,7 @@
The selected choice is invalid.
- گزینهی انتخابشده نامعتبر است.
+ گزینه انتخاب شده نامعتبر است.
The collection is invalid.
@@ -44,7 +44,7 @@
Please choose a valid date interval.
- لطفاً یک بازهی زمانی معتبر انتخاب کنید.
+ لطفاً یک بازه زمانی معتبر انتخاب کنید.
Please enter a valid date and time.
@@ -124,15 +124,15 @@
Please select a valid option.
- لطفاً یک گزینهی معتبر انتخاب کنید.
+ لطفاً یک گزینه معتبر انتخاب کنید.
Please select a valid range.
- لطفاً یک محدودهی معتبر انتخاب کنید.
+ لطفاً یک محدوده معتبر انتخاب کنید.
Please enter a valid week.
- لطفاً یک هفتهی معتبر وارد کنید.
+ لطفاً یک هفته معتبر وارد کنید.