diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php
deleted file mode 100644
index 80cf81b9340ce..0000000000000
--- a/.github/rm-invalid-lowest-lock-files.php
+++ /dev/null
@@ -1,158 +0,0 @@
- [], 'packages-dev' => []];
- $composerJsons[$composerJson['name']] = [$dir, $composerLock['packages'] + $composerLock['packages-dev'], getRelevantContent($composerJson)];
-}
-
-$referencedCommits = [];
-
-foreach ($composerJsons as list($dir, $lockedPackages)) {
- foreach ($lockedPackages as $lockedJson) {
- if (0 !== strpos($version = $lockedJson['version'], 'dev-') && '-dev' !== substr($version, -4)) {
- continue;
- }
-
- if (!isset($composerJsons[$name = $lockedJson['name']])) {
- echo "$dir/composer.lock references missing $name.\n";
- @unlink($dir.'/composer.lock');
- continue 2;
- }
-
- if (isset($composerJsons[$name][2]['repositories']) && !isset($lockedJson['repositories'])) {
- // the locked package has been patched locally but the lock references a commit,
- // which means the referencing package itself is not modified
- continue;
- }
-
- foreach (['minimum-stability', 'prefer-stable'] as $key) {
- if (array_key_exists($key, $composerJsons[$name][2])) {
- $lockedJson[$key] = $composerJsons[$name][2][$key];
- }
- }
-
- // use weak comparison to ignore ordering
- if (getRelevantContent($lockedJson) != $composerJsons[$name][2]) {
- echo "$dir/composer.lock is not in sync with $name.\n";
- @unlink($dir.'/composer.lock');
- continue 2;
- }
-
- if ($lockedJson['dist']['reference']) {
- $referencedCommits[$name][$lockedJson['dist']['reference']][] = $dir;
- }
- }
-}
-
-if (!$referencedCommits) {
- return;
-}
-
-@mkdir($_SERVER['HOME'].'/.cache/composer/repo/https---repo.packagist.org', 0777, true);
-
-$ch = null;
-$mh = curl_multi_init();
-$sh = curl_share_init();
-curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
-curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
-curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
-$chs = [];
-
-foreach ($referencedCommits as $name => $dirsByCommit) {
- $chs[] = $ch = [curl_init(), fopen($_SERVER['HOME'].'/.cache/composer/repo/https---repo.packagist.org/provider-'.strtr($name, '/', '$').'.json', 'wb')];
- curl_setopt($ch[0], CURLOPT_URL, 'https://repo.packagist.org/p/'.$name.'.json');
- curl_setopt($ch[0], CURLOPT_FILE, $ch[1]);
- curl_setopt($ch[0], CURLOPT_SHARE, $sh);
- curl_multi_add_handle($mh, $ch[0]);
-}
-
-do {
- curl_multi_exec($mh, $active);
- curl_multi_select($mh);
-} while ($active);
-
-foreach ($chs as list($ch, $fd)) {
- curl_multi_remove_handle($mh, $ch);
- curl_close($ch);
- fclose($fd);
-}
-
-foreach ($referencedCommits as $name => $dirsByCommit) {
- $repo = file_get_contents($_SERVER['HOME'].'/.cache/composer/repo/https---repo.packagist.org/provider-'.strtr($name, '/', '$').'.json');
- $repo = json_decode($repo, true);
-
- foreach ($repo['packages'][$name] as $version) {
- unset($referencedCommits[$name][$version['source']['reference']]);
- }
-}
-
-foreach ($referencedCommits as $name => $dirsByCommit) {
- foreach ($dirsByCommit as $dirs) {
- foreach ($dirs as $dir) {
- if (file_exists($dir.'/composer.lock')) {
- echo "$dir/composer.lock references old commit for $name.\n";
- @unlink($dir.'/composer.lock');
- }
- }
- }
-}
diff --git a/.travis.yml b/.travis.yml
index 009143743f598..bcb5e9ff8f69b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -279,11 +279,7 @@ install:
[[ ! $X ]] || (exit 1)
elif [[ $deps = low ]]; then
- [[ -e ~/php-ext/composer-lowest.lock.tar ]] && tar -xf ~/php-ext/composer-lowest.lock.tar
- tar -cf ~/php-ext/composer-lowest.lock.tar --files-from /dev/null
- php .github/rm-invalid-lowest-lock-files.php $COMPONENTS
- echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && ([ -e composer.lock ] && ${COMPOSER_UP/update/install} || $COMPOSER_UP --prefer-lowest --prefer-stable) && $PHPUNIT_X'"
- echo "$COMPONENTS" | xargs -n1 -I{} tar --append -f ~/php-ext/composer-lowest.lock.tar {}/composer.lock
+ echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT_X'"
else
if [[ $PHP = 8.0* ]]; then
# add return types before running the test suite
diff --git a/CHANGELOG-5.2.md b/CHANGELOG-5.2.md
index 68a57b4be09f1..5e5f455254f7a 100644
--- a/CHANGELOG-5.2.md
+++ b/CHANGELOG-5.2.md
@@ -7,6 +7,46 @@ in 5.2 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.2.0...v5.2.1
+* 5.2.6 (2021-03-29)
+
+ * bug #40598 [Form] error if the input string couldn't be parsed as a date (xabbuh)
+ * bug #40587 [HttpClient] fix using stream_copy_to_stream() with responses cast to php streams (nicolas-grekas)
+ * bug #40510 [Form] IntegerType: Always use en for IntegerToLocalizedStringTransformer (Warxcell)
+ * bug #40593 Uses the correct assignment action for console options depending if they are short or long (topikito)
+ * bug #40535 [HttpKernel] ConfigDataCollector to return known data without the need of a Kernel (topikito)
+ * bug #40552 [Translation] Fix update existing key with existing +int-icu domain (Alexis)
+ * bug #40541 Fixed parsing deprecated definitions without message key (adamwojs)
+ * bug #40537 [Security] Handle properly 'auto' option for remember me cookie security (fliespl)
+ * bug #40524 [Console] fix emojis messing up the line width (MarionLeHerisson)
+ * bug #40506 [Validator] Avoid triggering the autoloader for user-input values (Seldaek)
+ * bug #40544 [FrameworkBundle] ensure TestBrowserToken::$firewallName is serialized (kbond)
+ * bug #40547 [RateLimiter] Security hardening - Rate limiter (jderusse)
+ * bug #40538 [HttpClient] remove using $http_response_header (nicolas-grekas)
+ * bug #40508 [PhpUnitBridge] fix reporting deprecations from DebugClassLoader (nicolas-grekas)
+ * bug #40497 [HttpFoundation] enable HTTP method overrides as early as possible with the HTTP cache (xabbuh)
+ * bug #40348 [Console] Fix line wrapping for decorated text in block output (grasmash)
+ * bug #40499 [Inflector][String] Fixed pluralize "coupon" (Nyholm)
+ * bug #40494 [PhpUnitBridge] fix compat with symfony/debug (nicolas-grekas)
+ * bug #40453 [VarDumper] Adds support for ReflectionUnionType to VarDumper (Michael Nelson, michaeldnelson)
+ * bug #40460 Correctly clear lines for multi-line progress bar messages (grasmash)
+ * bug #40490 [Security] Add XML support for authenticator manager (wouterj)
+ * bug #40242 [ErrorHandler] Fix error caused by `include` + open_basedir (stlrnz)
+ * bug #40368 [FrameworkBundle] Make the TestBrowserToken interchangeable with other tokens (Seldaek)
+ * bug #40450 [Console] ProgressBar clears too many lines on update (danepowell)
+ * bug #40178 [FrameworkBundle] Exclude unreadable files when executing About command (michaljusiega)
+ * bug #40472 [Bridge\Twig] Add 'form-control-range' for range input type (Oviglo)
+ * bug #40481 make async-ses required (jderusse)
+ * bug #39866 [Mime] Escape commas in address names (YaFou)
+ * bug #40373 Check if templating engine supports given view (fritzmg)
+ * bug #39992 [Security] Refresh original user in SwitchUserListener (AndrolGenhald)
+ * bug #40446 [TwigBridge] Fix "Serialization of 'Closure'" error when rendering an TemplatedEmail (jderusse)
+ * bug #40416 Fix `ConstraintViolation#getMessageTemplate()` to always return `string` (Ocramius)
+ * bug #40425 [DoctrineBridge] Fix eventListener initialization when eventSubscriber constructor dispatch an event (jderusse)
+ * bug #40313 [FrameworkBundle] Fix PropertyAccess definition when not in debug (PedroTroller)
+ * bug #40417 [Form] clear unchecked choice radio boxes even if clear missing is set to false (xabbuh)
+ * bug #40388 [ErrorHandler] Added missing type annotations to FlattenException (derrabus)
+ * bug #40407 [TwigBridge] Allow version 3 of the Twig extra packages (derrabus)
+
* 5.2.5 (2021-03-10)
* bug #40415 Fix `ConstraintViolation#getPropertyPath()` to always return `string` (Ocramius)
diff --git a/composer.json b/composer.json
index fc7535421b83b..fcc78bf789953 100644
--- a/composer.json
+++ b/composer.json
@@ -149,9 +149,9 @@
"symfony/phpunit-bridge": "^5.2",
"symfony/security-acl": "~2.8|~3.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
- "twig/cssinliner-extra": "^2.12",
- "twig/inky-extra": "^2.12",
- "twig/markdown-extra": "^2.12"
+ "twig/cssinliner-extra": "^2.12|^3",
+ "twig/inky-extra": "^2.12|^3",
+ "twig/markdown-extra": "^2.12|^3"
},
"conflict": {
"doctrine/dbal": "<2.10",
diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
index 9b3c1595a41f0..1ee4f54ded8e1 100644
--- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
+++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
@@ -177,6 +177,7 @@ private function initializeSubscribers()
if (!isset($this->listeners[$event])) {
$this->listeners[$event] = [];
}
+ unset($this->initialized[$event]);
$this->listeners[$event] += $listeners;
}
$this->subscribers = [];
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
index 3e3ebef48c7c3..b4d79e7ba46d7 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
@@ -11,6 +11,8 @@
namespace Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestSuite;
use PHPUnit\Util\Test;
use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor;
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
@@ -81,47 +83,56 @@ public function __construct($message, array $trace, $file)
$this->triggeringFile = isset($trace[1 + $j]['args'][1]) ? realpath($trace[1 + $j]['args'][1]) : (new \ReflectionClass($class))->getFileName();
$this->getOriginalFilesStack();
array_splice($this->originalFilesStack, 0, $j, [$this->triggeringFile]);
+
+ if (preg_match('/(?|"([^"]++)" that is deprecated|should implement method "(?:static )?([^:]++))/', $message, $m) || preg_match('/^(?:The|Method) "([^":]++)/', $message, $m)) {
+ $this->triggeringFile = (new \ReflectionClass($m[1]))->getFileName();
+ array_unshift($this->originalFilesStack, $this->triggeringFile);
+ }
}
break;
}
}
- if (isset($line['object']) || isset($line['class'])) {
- set_error_handler(function () {});
- $parsedMsg = unserialize($this->message);
- restore_error_handler();
- if ($parsedMsg && isset($parsedMsg['deprecation'])) {
- $this->message = $parsedMsg['deprecation'];
- $this->originClass = $parsedMsg['class'];
- $this->originMethod = $parsedMsg['method'];
- if (isset($parsedMsg['files_stack'])) {
- $this->originalFilesStack = $parsedMsg['files_stack'];
- }
- // If the deprecation has been triggered via
- // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
- // then we need to use the serialized information to determine
- // if the error has been triggered from vendor code.
- if (isset($parsedMsg['triggering_file'])) {
- $this->triggeringFile = $parsedMsg['triggering_file'];
- }
+ if (!isset($line['object']) && !isset($line['class'])) {
+ return;
+ }
- return;
+ set_error_handler(function () {});
+ $parsedMsg = unserialize($this->message);
+ restore_error_handler();
+ if ($parsedMsg && isset($parsedMsg['deprecation'])) {
+ $this->message = $parsedMsg['deprecation'];
+ $this->originClass = $parsedMsg['class'];
+ $this->originMethod = $parsedMsg['method'];
+ if (isset($parsedMsg['files_stack'])) {
+ $this->originalFilesStack = $parsedMsg['files_stack'];
+ }
+ // If the deprecation has been triggered via
+ // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
+ // then we need to use the serialized information to determine
+ // if the error has been triggered from vendor code.
+ if (isset($parsedMsg['triggering_file'])) {
+ $this->triggeringFile = $parsedMsg['triggering_file'];
}
- if (!isset($line['class'], $trace[$i - 2]['function']) || 0 !== strpos($line['class'], SymfonyTestsListenerFor::class)) {
- $this->originClass = isset($line['object']) ? \get_class($line['object']) : $line['class'];
- $this->originMethod = $line['function'];
+ return;
+ }
- return;
- }
+ if (!isset($line['class'], $trace[$i - 2]['function']) || 0 !== strpos($line['class'], SymfonyTestsListenerFor::class)) {
+ $this->originClass = isset($line['object']) ? \get_class($line['object']) : $line['class'];
+ $this->originMethod = $line['function'];
+
+ return;
+ }
- if ('trigger_error' !== $trace[$i - 2]['function'] || isset($trace[$i - 2]['class'])) {
- $this->originClass = \get_class($line['args'][0]);
- $this->originMethod = $line['args'][0]->getName();
+ $test = isset($line['args'][0]) ? $line['args'][0] : null;
- return;
- }
+ if (($test instanceof TestCase || $test instanceof TestSuite) && ('trigger_error' !== $trace[$i - 2]['function'] || isset($trace[$i - 2]['class']))) {
+ $this->originClass = \get_class($test);
+ $this->originMethod = $test->getName();
+
+ return;
}
}
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_deprecation.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_deprecation.phpt
new file mode 100644
index 0000000000000..a6b0133af93ed
--- /dev/null
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_deprecation.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Test that a deprecation from the DebugClassLoader triggered by an app class extending a vendor one is considered direct.
+--FILE--
+
+--EXPECTF--
+Remaining direct deprecation notices (1)
+
+ 1x: The "App\Services\ExtendsDeprecatedFromVendor" class extends "fcy\lib\DeprecatedClass" that is deprecated.
+ 1x in DebugClassLoader::loadClass from Symfony\Component\ErrorHandler
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_app/ExtendsDeprecatedFromVendor.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_app/ExtendsDeprecatedFromVendor.php
new file mode 100644
index 0000000000000..b4305e0d08a55
--- /dev/null
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_app/ExtendsDeprecatedFromVendor.php
@@ -0,0 +1,9 @@
+getTextTemplate(), $message->getHtmlTemplate()]));
+ $currentRenderingKey = $this->getFingerPrint($message);
if ($previousRenderingKey === $currentRenderingKey) {
return;
}
@@ -77,6 +77,23 @@ public function render(Message $message): void
$message->context($message->getContext() + [__CLASS__ => $currentRenderingKey]);
}
+ private function getFingerPrint(TemplatedEmail $message): string
+ {
+ $messageContext = $message->getContext();
+ unset($messageContext[__CLASS__]);
+
+ $payload = [$messageContext, $message->getTextTemplate(), $message->getHtmlTemplate()];
+ try {
+ $serialized = serialize($payload);
+ } catch (\Exception $e) {
+ // Serialization of 'Closure' is not allowed
+ // Happens when context contain a closure, in that case, we assume that context always change.
+ $serialized = random_bytes(8);
+ }
+
+ return md5($serialized);
+ }
+
private function convertHtmlToText(string $html): string
{
if (null !== $this->converter) {
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
index 86e2715488338..c990d81370f3c 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
@@ -134,9 +134,15 @@
{% endblock %}
{% block form_widget_simple -%}
- {% if type is not defined or type != 'hidden' %}
- {%- set attr = attr|merge({class: (attr.class|default('') ~ (type|default('') == 'file' ? ' custom-file-input' : ' form-control'))|trim}) -%}
- {% endif %}
+ {%- if type is not defined or type != 'hidden' -%}
+ {%- set className = ' form-control' -%}
+ {%- if type|default('') == 'file' -%}
+ {%- set className = ' custom-file-input' -%}
+ {%- elseif type|default('') == 'range' -%}
+ {%- set className = ' form-control-range' -%}
+ {%- endif -%}
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ className)|trim}) -%}
+ {%- endif -%}
{%- if type is defined and (type == 'range' or type == 'color') %}
{# Attribute "required" is not supported #}
{%- set required = false -%}
@@ -144,12 +150,12 @@
{{- parent() -}}
{%- endblock form_widget_simple %}
-{%- block widget_attributes -%}
- {%- if not valid %}
+{% block widget_attributes -%}
+ {%- if not valid -%}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' is-invalid')|trim}) %}
- {% endif -%}
+ {%- endif -%}
{{ parent() }}
-{%- endblock widget_attributes -%}
+{%- endblock widget_attributes %}
{% block button_widget -%}
{%- set attr = attr|merge({class: (attr.class|default('btn-secondary') ~ ' btn')|trim}) -%}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php
index d786434614bd4..4c92d628850e1 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php
@@ -19,6 +19,7 @@
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\PercentType;
use Symfony\Component\Form\Extension\Core\Type\RadioType;
+use Symfony\Component\Form\Extension\Core\Type\RangeType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormError;
@@ -1227,6 +1228,41 @@ public function testPercentCustomSymbol()
[contains(.., "‱")]
]
]
+'
+ );
+ }
+
+ public function testRange()
+ {
+ $form = $this->factory->createNamed('name', RangeType::class, 42, ['attr' => ['min' => 5]]);
+
+ $this->assertWidgetMatchesXpath(
+ $form->createView(),
+ ['attr' => ['class' => 'my&class']],
+'/input
+ [@type="range"]
+ [@name="name"]
+ [@value="42"]
+ [@min="5"]
+ [@class="my&class form-control-range"]
+'
+ );
+ }
+
+ public function testRangeWithMinMaxValues()
+ {
+ $form = $this->factory->createNamed('name', RangeType::class, 42, ['attr' => ['min' => 5, 'max' => 57]]);
+
+ $this->assertWidgetMatchesXpath(
+ $form->createView(),
+ ['attr' => ['class' => 'my&class']],
+'/input
+ [@type="range"]
+ [@name="name"]
+ [@value="42"]
+ [@min="5"]
+ [@max="57"]
+ [@class="my&class form-control-range"]
'
);
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php
index f13ab213c3c4f..8ff343b684b5e 100644
--- a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php
@@ -100,6 +100,27 @@ public function testRenderedOnce()
$this->assertEquals('reset', $email->getTextBody());
}
+ public function testRenderedOnceUnserializableContext()
+ {
+ $twig = new Environment(new ArrayLoader([
+ 'text' => 'Text',
+ ]));
+ $renderer = new BodyRenderer($twig);
+ $email = (new TemplatedEmail())
+ ->to('fabien@symfony.com')
+ ->from('helene@symfony.com')
+ ;
+ $email->textTemplate('text');
+ $email->context([
+ 'foo' => static function () {
+ return 'bar';
+ },
+ ]);
+
+ $renderer->render($email);
+ $this->assertEquals('Text', $email->getTextBody());
+ }
+
private function prepareEmail(?string $text, ?string $html, array $context = []): TemplatedEmail
{
$twig = new Environment(new ArrayLoader([
diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json
index f167ccd927f43..8012df7ae6d56 100644
--- a/src/Symfony/Bridge/Twig/composer.json
+++ b/src/Symfony/Bridge/Twig/composer.json
@@ -47,9 +47,9 @@
"symfony/expression-language": "^4.4|^5.0",
"symfony/web-link": "^4.4|^5.0",
"symfony/workflow": "^5.2",
- "twig/cssinliner-extra": "^2.12",
- "twig/inky-extra": "^2.12",
- "twig/markdown-extra": "^2.12"
+ "twig/cssinliner-extra": "^2.12|^3",
+ "twig/inky-extra": "^2.12|^3",
+ "twig/markdown-extra": "^2.12|^3"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.2.2",
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
index 279ef5062faaa..be5f2474448ac 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
@@ -113,7 +113,9 @@ private static function formatFileSize(string $path): string
} else {
$size = 0;
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS | \RecursiveDirectoryIterator::FOLLOW_SYMLINKS)) as $file) {
- $size += $file->getSize();
+ if ($file->isReadable()) {
+ $size += $file->getSize();
+ }
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index c6cd60cc32fb1..00892d8847951 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -1997,7 +1997,7 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
if (!$container->getParameter('kernel.debug')) {
$propertyAccessDefinition->setFactory([PropertyAccessor::class, 'createCache']);
- $propertyAccessDefinition->setArguments([null, 0, $version, new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]);
+ $propertyAccessDefinition->setArguments(['', 0, $version, new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]);
$propertyAccessDefinition->addTag('cache.pool', ['clearer' => 'cache.system_clearer']);
$propertyAccessDefinition->addTag('monolog.logger', ['channel' => 'cache']);
} else {
diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
index 35ea73c235771..45b2ca785603e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
+++ b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
@@ -18,6 +18,7 @@
use Symfony\Component\HttpKernel\HttpCache\Store;
use Symfony\Component\HttpKernel\HttpCache\StoreInterface;
use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelInterface;
/**
@@ -62,6 +63,15 @@ public function __construct(KernelInterface $kernel, $cache = null, SurrogateInt
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($this->options, $this->getOptions()));
}
+ public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true)
+ {
+ if ($this->kernel->getContainer()->getParameter('kernel.http_method_override')) {
+ Request::enableHttpMethodParameterOverride();
+ }
+
+ return parent::handle($request, $type, $catch);
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
index 40381e34aa310..dff1eea251041 100644
--- a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
+++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
@@ -120,7 +120,7 @@ public function loginUser($user, string $firewallContext = 'main'): self
throw new \LogicException(sprintf('The first argument of "%s" must be instance of "%s", "%s" provided.', __METHOD__, UserInterface::class, \is_object($user) ? \get_class($user) : \gettype($user)));
}
- $token = new TestBrowserToken($user->getRoles(), $user);
+ $token = new TestBrowserToken($user->getRoles(), $user, $firewallContext);
$token->setAuthenticated(true);
$session = $this->getContainer()->get('session');
$session->set('_security_'.$firewallContext, serialize($token));
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php b/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php
index 08f7b107d03a4..7580743f6d5cb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php
@@ -21,17 +21,38 @@
*/
class TestBrowserToken extends AbstractToken
{
- public function __construct(array $roles = [], UserInterface $user = null)
+ private $firewallName;
+
+ public function __construct(array $roles = [], UserInterface $user = null, string $firewallName = 'main')
{
parent::__construct($roles);
if (null !== $user) {
$this->setUser($user);
}
+
+ $this->firewallName = $firewallName;
+ }
+
+ public function getFirewallName(): string
+ {
+ return $this->firewallName;
}
public function getCredentials()
{
return null;
}
+
+ public function __serialize(): array
+ {
+ return [$this->firewallName, parent::__serialize()];
+ }
+
+ public function __unserialize(array $data): void
+ {
+ [$this->firewallName, $parentData] = $data;
+
+ parent::__unserialize($parentData);
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/AboutCommand/AboutCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/AboutCommand/AboutCommandTest.php
new file mode 100644
index 0000000000000..8a1fcf93caabd
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/AboutCommand/AboutCommandTest.php
@@ -0,0 +1,90 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Command\AboutCommand;
+
+use Symfony\Bundle\FrameworkBundle\Command\AboutCommand;
+use Symfony\Bundle\FrameworkBundle\Console\Application;
+use Symfony\Bundle\FrameworkBundle\Tests\Command\AboutCommand\Fixture\TestAppKernel;
+use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
+use Symfony\Component\Console\Tester\CommandTester;
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Filesystem\Filesystem;
+
+class AboutCommandTest extends TestCase
+{
+ /** @var Filesystem */
+ private $fs;
+
+ protected function setUp(): void
+ {
+ $this->fs = new Filesystem();
+ }
+
+ public function testAboutWithReadableFiles()
+ {
+ $kernel = new TestAppKernel('test', true);
+ $this->fs->mkdir($kernel->getProjectDir());
+
+ $this->fs->dumpFile($kernel->getCacheDir().'/readable_file', 'The file content.');
+ $this->fs->chmod($kernel->getCacheDir().'/readable_file', 0777);
+
+ $tester = $this->createCommandTester($kernel);
+ $ret = $tester->execute([]);
+
+ $this->assertSame(0, $ret);
+ $this->assertStringContainsString('Cache directory', $tester->getDisplay());
+ $this->assertStringContainsString('Log directory', $tester->getDisplay());
+
+ $this->fs->chmod($kernel->getCacheDir().'/readable_file', 0777);
+
+ try {
+ $this->fs->remove($kernel->getProjectDir());
+ } catch (IOException $e) {
+ }
+ }
+
+ public function testAboutWithUnreadableFiles()
+ {
+ $kernel = new TestAppKernel('test', true);
+ $this->fs->mkdir($kernel->getProjectDir());
+
+ // skip test on Windows; PHP can't easily set file as unreadable on Windows
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('This test cannot run on Windows.');
+ }
+
+ $this->fs->dumpFile($kernel->getCacheDir().'/unreadable_file', 'The file content.');
+ $this->fs->chmod($kernel->getCacheDir().'/unreadable_file', 0222);
+
+ $tester = $this->createCommandTester($kernel);
+ $ret = $tester->execute([]);
+
+ $this->assertSame(0, $ret);
+ $this->assertStringContainsString('Cache directory', $tester->getDisplay());
+ $this->assertStringContainsString('Log directory', $tester->getDisplay());
+
+ $this->fs->chmod($kernel->getCacheDir().'/unreadable_file', 0777);
+
+ try {
+ $this->fs->remove($kernel->getProjectDir());
+ } catch (IOException $e) {
+ }
+ }
+
+ private function createCommandTester(TestAppKernel $kernel): CommandTester
+ {
+ $application = new Application($kernel);
+ $application->add(new AboutCommand());
+
+ return new CommandTester($application->find('about'));
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/AboutCommand/Fixture/TestAppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/AboutCommand/Fixture/TestAppKernel.php
new file mode 100644
index 0000000000000..c15bf83cb1cf8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/AboutCommand/Fixture/TestAppKernel.php
@@ -0,0 +1,40 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Command\AboutCommand\Fixture;
+
+use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+use Symfony\Component\Config\Loader\LoaderInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Kernel;
+
+class TestAppKernel extends Kernel
+{
+ public function registerBundles(): iterable
+ {
+ return [
+ new FrameworkBundle(),
+ ];
+ }
+
+ public function getProjectDir(): string
+ {
+ return __DIR__.'/test';
+ }
+
+ public function registerContainerConfiguration(LoaderInterface $loader)
+ {
+ }
+
+ protected function build(ContainerBuilder $container)
+ {
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 960eda35d0b62..5cae48bd6ecc2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -1696,7 +1696,7 @@ protected function createContainerFromFile($file, $data = [], $resetCompilerPass
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
}
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([new LoggerPass()]);
- $container->getCompilerPassConfig()->setBeforeRemovingPasses([new AddConstraintValidatorsPass(), new TranslatorPass('translator.default', 'translation.reader')]);
+ $container->getCompilerPassConfig()->setBeforeRemovingPasses([new AddConstraintValidatorsPass(), new TranslatorPass()]);
$container->getCompilerPassConfig()->setAfterRemovingPasses([new AddAnnotationsCachedReaderPass()]);
if (!$compile) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php
index 15ff182c6fed5..2e46e896bca7c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php
@@ -14,5 +14,4 @@
return [
new FrameworkBundle(),
- new TestBundle(),
];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/TestBrowserTokenTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/TestBrowserTokenTest.php
new file mode 100644
index 0000000000000..8c5387590a43a
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/TestBrowserTokenTest.php
@@ -0,0 +1,16 @@
+assertSame('main', $token->getFirewallName());
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginLinkFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginLinkFactory.php
index 3afddb3d35f3b..0b99f281e9a94 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginLinkFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginLinkFactory.php
@@ -31,7 +31,7 @@ class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryIn
public function addConfiguration(NodeDefinition $node)
{
/** @var NodeBuilder $builder */
- $builder = $node->children();
+ $builder = $node->fixXmlConfig('signature_property', 'signature_properties')->children();
$builder
->scalarNode('check_route')
@@ -98,6 +98,10 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
if (null !== $config['max_uses'] && !isset($config['used_link_cache'])) {
$config['used_link_cache'] = 'security.authenticator.cache.expired_links';
+ $defaultCacheDefinition = $container->getDefinition($config['used_link_cache']);
+ if (!$defaultCacheDefinition->hasTag('cache.pool')) {
+ $defaultCacheDefinition->addTag('cache.pool');
+ }
}
$expiredStorageId = null;
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
index c0aa37ec88712..1ff09a48ac5b9 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
@@ -64,7 +64,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
}
if (!class_exists(RateLimiterFactory::class)) {
- throw new \LogicException('Login throttling requires symfony/rate-limiter to be installed and enabled.');
+ throw new \LogicException('Login throttling requires the Rate Limiter component. Try running "composer require symfony/rate-limiter".');
}
if (!isset($config['limiter'])) {
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
index 884c7b5721f20..27ec6ff9e0ac6 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
@@ -108,7 +108,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
$container
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remember_me'))
->replaceArgument(0, new Reference($rememberMeServicesId))
- ->replaceArgument(3, array_intersect_key($config, $this->options))
+ ->replaceArgument(3, $container->getDefinition($rememberMeServicesId)->getArgument(3))
;
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
@@ -201,7 +201,12 @@ private function createRememberMeServices(ContainerBuilder $container, string $i
}
// remember-me options
- $rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
+ $mergedOptions = array_intersect_key($config, $this->options);
+ if ('auto' === $mergedOptions['secure']) {
+ $mergedOptions['secure'] = null;
+ }
+
+ $rememberMeServices->replaceArgument(3, $mergedOptions);
if ($config['user_providers']) {
$userProviders = [];
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
index 8ff0d5e46da0d..509ac0b0534f7 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
@@ -23,6 +23,7 @@
+
@@ -141,6 +142,7 @@
+
@@ -160,6 +162,7 @@
+
@@ -231,6 +234,7 @@
+
@@ -283,6 +287,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_login_link.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_login_link.php
index 2efb089262cfe..2248b5e8eeb7d 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_login_link.php
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_login_link.php
@@ -51,7 +51,6 @@
->set('security.authenticator.cache.expired_links')
->parent('cache.app')
->private()
- ->tag('cache.pool')
->set('security.authenticator.firewall_aware_login_link_handler', FirewallAwareLoginLinkHandler::class)
->args([
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
index 072e33aca6f4d..47d3033a25582 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
@@ -21,6 +21,7 @@
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
+use Symfony\Component\Security\Http\Authentication\AuthenticatorManager;
abstract class CompleteConfigurationTest extends TestCase
{
@@ -28,6 +29,38 @@ abstract protected function getLoader(ContainerBuilder $container);
abstract protected function getFileExtension();
+ public function testAuthenticatorManager()
+ {
+ $container = $this->getContainer('authenticator_manager');
+
+ $this->assertEquals(AuthenticatorManager::class, $container->getDefinition('security.authenticator.manager.main')->getClass());
+
+ // login link
+ $expiredStorage = $container->getDefinition($expiredStorageId = 'security.authenticator.expired_login_link_storage.main');
+ $this->assertEquals('cache.redis', (string) $expiredStorage->getArgument(0));
+ $this->assertEquals(3600, (string) $expiredStorage->getArgument(1));
+
+ $linker = $container->getDefinition($linkerId = 'security.authenticator.login_link_handler.main');
+ $this->assertEquals(['id', 'email'], $linker->getArgument(3));
+ $this->assertEquals([
+ 'route_name' => 'login_check',
+ 'lifetime' => 3600,
+ 'max_uses' => 1,
+ ], $linker->getArgument(5));
+ $this->assertEquals($expiredStorageId, (string) $linker->getArgument(6));
+
+ $authenticator = $container->getDefinition('security.authenticator.login_link.main');
+ $this->assertEquals($linkerId, (string) $authenticator->getArgument(0));
+ $this->assertEquals([
+ 'check_route' => 'login_check',
+ 'check_post_only' => true,
+ ], $authenticator->getArgument(4));
+
+ // login throttling
+ $listener = $container->getDefinition('security.listener.login_throttling.main');
+ $this->assertEquals('app.rate_limiter', (string) $listener->getArgument(1));
+ }
+
public function testRolesHierarchy()
{
$container = $this->getContainer('container1');
@@ -648,6 +681,7 @@ protected function getContainer($file)
$container->setParameter('kernel.debug', false);
$container->setParameter('request_listener.http_port', 80);
$container->setParameter('request_listener.https_port', 443);
+ $container->register('cache.app', \stdClass::class);
$security = new SecurityExtension();
$container->registerExtension($security);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/authenticator_manager.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/authenticator_manager.php
new file mode 100644
index 0000000000000..31a37fe2103f9
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/authenticator_manager.php
@@ -0,0 +1,20 @@
+loadFromExtension('security', [
+ 'enable_authenticator_manager' => true,
+ 'firewalls' => [
+ 'main' => [
+ 'login_link' => [
+ 'check_route' => 'login_check',
+ 'check_post_only' => true,
+ 'signature_properties' => ['id', 'email'],
+ 'max_uses' => 1,
+ 'lifetime' => 3600,
+ 'used_link_cache' => 'cache.redis',
+ ],
+ 'login_throttling' => [
+ 'limiter' => 'app.rate_limiter',
+ ],
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/authenticator_manager.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/authenticator_manager.xml
new file mode 100644
index 0000000000000..2a3b643a6e905
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/authenticator_manager.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+ id
+ email
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/authenticator_manager.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/authenticator_manager.yml
new file mode 100644
index 0000000000000..8ff11698ae772
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/authenticator_manager.yml
@@ -0,0 +1,13 @@
+security:
+ enable_authenticator_manager: true
+ firewalls:
+ main:
+ login_link:
+ check_route: login_check
+ check_post_only: true
+ signature_properties: [id, email]
+ max_uses: 1
+ lifetime: 3600
+ used_link_cache: 'cache.redis'
+ login_throttling:
+ limiter: 'app.rate_limiter'
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeCookieTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeCookieTest.php
new file mode 100644
index 0000000000000..6bfa1ed438732
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeCookieTest.php
@@ -0,0 +1,33 @@
+createClient(['test_case' => 'RememberMeCookie', 'root_config' => 'config.yml']);
+
+ $client->request('POST', '/login', [
+ '_username' => 'test',
+ '_password' => 'test',
+ ], [], [
+ 'HTTPS' => (int) $https,
+ ]);
+
+ $cookies = $client->getResponse()->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
+
+ $this->assertEquals($expectedSecureFlag, $cookies['']['/']['REMEMBERME']->isSecure());
+ }
+
+ public function getSessionRememberMeSecureCookieFlagAutoHttpsMap()
+ {
+ return [
+ [true, true],
+ [false, false],
+ ];
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/RememberMeCookie/bundles.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/RememberMeCookie/bundles.php
new file mode 100644
index 0000000000000..8d4a02497947a
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/RememberMeCookie/bundles.php
@@ -0,0 +1,9 @@
+ a:hover {
display: block;
text-decoration: none;
+ background-color: transparent;
color: inherit;
}
@@ -243,6 +244,7 @@ div.sf-toolbar .sf-toolbar-block a:hover {
padding: 0 10px;
}
.sf-toolbar-block-request .sf-toolbar-info-piece a {
+ background-color: transparent;
text-decoration: none;
}
.sf-toolbar-block-request .sf-toolbar-info-piece a:hover {
diff --git a/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php b/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php
index f704bbfe0e49f..6aa94c2c63383 100644
--- a/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php
+++ b/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Cache\Tests\Marshaller;
+namespace Symfony\Component\Cache\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\TraceableAdapter;
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
index 65f54f8013dd1..66e8c37181858 100644
--- a/src/Symfony/Component/Console/Command/Command.php
+++ b/src/Symfony/Component/Console/Command/Command.php
@@ -395,9 +395,9 @@ public function addArgument(string $name, int $mode = null, string $description
/**
* Adds an option.
*
- * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
- * @param int|null $mode The option mode: One of the InputOption::VALUE_* constants
- * @param string|string[]|int|bool|null $default The default value (must be null for InputOption::VALUE_NONE)
+ * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
+ * @param int|null $mode The option mode: One of the InputOption::VALUE_* constants
+ * @param string|string[]|bool|null $default The default value (must be null for InputOption::VALUE_NONE)
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*
diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php
index f82dd286fc3b5..acec994db83c4 100644
--- a/src/Symfony/Component/Console/Helper/Helper.php
+++ b/src/Symfony/Component/Console/Helper/Helper.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
+use Symfony\Component\String\UnicodeString;
/**
* Helper is the base class for all helper classes.
@@ -45,7 +46,11 @@ public function getHelperSet()
*/
public static function strlen(?string $string)
{
- $string = (string) $string;
+ $string ?? $string = '';
+
+ if (preg_match('//u', $string)) {
+ return (new UnicodeString($string))->width(false);
+ }
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return \strlen($string);
@@ -59,9 +64,9 @@ public static function strlen(?string $string)
*
* @return string The string subset
*/
- public static function substr(string $string, int $from, int $length = null)
+ public static function substr(?string $string, int $from, int $length = null)
{
- $string = (string) $string;
+ $string ?? $string = '';
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return substr($string, $from, $length);
@@ -116,17 +121,23 @@ public static function formatMemory(int $memory)
return sprintf('%d B', $memory);
}
- public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
+ public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string)
{
- return self::strlen(self::removeDecoration($formatter, $string));
+ $string = self::removeDecoration($formatter, $string);
+
+ if (preg_match('//u', $string)) {
+ return (new UnicodeString($string))->width(true);
+ }
+
+ return self::strlen($string);
}
- public static function removeDecoration(OutputFormatterInterface $formatter, $string)
+ public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)
{
$isDecorated = $formatter->isDecorated();
$formatter->setDecorated(false);
// remove <...> formatting
- $string = $formatter->format($string);
+ $string = $formatter->format($string ?? '');
// remove already formatted characters
$string = preg_replace("/\033\[[^m]*m/", '', $string);
$formatter->setDecorated($isDecorated);
diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php
index a3aa4809779f4..61c471424ad4a 100644
--- a/src/Symfony/Component/Console/Helper/ProgressBar.php
+++ b/src/Symfony/Component/Console/Helper/ProgressBar.php
@@ -462,8 +462,15 @@ private function overwrite(string $message): void
if ($this->overwrite) {
if (null !== $this->previousMessage) {
if ($this->output instanceof ConsoleSectionOutput) {
- $lines = floor(Helper::strlen($message) / $this->terminal->getWidth()) + $this->formatLineCount + 1;
- $this->output->clear($lines);
+ $messageLines = explode("\n", $message);
+ $lineCount = \count($messageLines);
+ foreach ($messageLines as $messageLine) {
+ $messageLineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $messageLine);
+ if ($messageLineLength > $this->terminal->getWidth()) {
+ $lineCount += floor($messageLineLength / $this->terminal->getWidth());
+ }
+ }
+ $this->output->clear($lineCount);
} else {
if ($this->formatLineCount > 0) {
$this->cursor->moveUp($this->formatLineCount);
diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php
index c0fb5461fc660..5bf8186b8fbf8 100644
--- a/src/Symfony/Component/Console/Helper/QuestionHelper.php
+++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php
@@ -311,7 +311,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu
$remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
$output->write($remainingCharacters);
$fullChoice .= $remainingCharacters;
- $i = self::strlen($fullChoice);
+ $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding);
$matches = array_filter(
$autocomplete($ret),
diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php
index 66f0bedc3626b..5c1e2f63ae58f 100644
--- a/src/Symfony/Component/Console/Input/ArrayInput.php
+++ b/src/Symfony/Component/Console/Input/ArrayInput.php
@@ -108,12 +108,13 @@ public function __toString()
$params = [];
foreach ($this->parameters as $param => $val) {
if ($param && \is_string($param) && '-' === $param[0]) {
+ $glue = ('-' === $param[1]) ? '=' : ' ';
if (\is_array($val)) {
foreach ($val as $v) {
- $params[] = $param.('' != $v ? '='.$this->escapeToken($v) : '');
+ $params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');
}
} else {
- $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
+ $params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');
}
} else {
$params[] = \is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);
diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php
index 66f857a6c0d3b..a8e956db55b19 100644
--- a/src/Symfony/Component/Console/Input/InputOption.php
+++ b/src/Symfony/Component/Console/Input/InputOption.php
@@ -33,11 +33,11 @@ class InputOption
private $description;
/**
- * @param string $name The option name
- * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
- * @param int|null $mode The option mode: One of the VALUE_* constants
- * @param string $description A description text
- * @param string|string[]|int|bool|null $default The default value (must be null for self::VALUE_NONE)
+ * @param string $name The option name
+ * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
+ * @param int|null $mode The option mode: One of the VALUE_* constants
+ * @param string $description A description text
+ * @param string|string[]|bool|null $default The default value (must be null for self::VALUE_NONE)
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
@@ -149,7 +149,7 @@ public function isArray()
/**
* Sets the default value.
*
- * @param string|string[]|int|bool|null $default The default value
+ * @param string|string[]|bool|null $default The default value
*
* @throws LogicException When incorrect default value is given
*/
@@ -173,7 +173,7 @@ public function setDefault($default = null)
/**
* Returns the default value.
*
- * @return string|string[]|int|bool|null The default value
+ * @return string|string[]|bool|null The default value
*/
public function getDefault()
{
diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php
index a1b019ca0a781..075fe6621cc1f 100644
--- a/src/Symfony/Component/Console/Style/SymfonyStyle.php
+++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php
@@ -476,7 +476,12 @@ private function createBlock(iterable $messages, string $type = null, string $st
$message = OutputFormatter::escape($message);
}
- $lines = array_merge($lines, explode(\PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, \PHP_EOL, true)));
+ $decorationLength = Helper::strlen($message) - Helper::strlenWithoutDecoration($this->getFormatter(), $message);
+ $messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);
+ $messageLines = explode(\PHP_EOL, wordwrap($message, $messageLineLength, \PHP_EOL, true));
+ foreach ($messageLines as $messageLine) {
+ $lines[] = $messageLine;
+ }
if (\count($messages) > 1 && $key < \count($messages) - 1) {
$lines[] = '';
@@ -496,7 +501,7 @@ private function createBlock(iterable $messages, string $type = null, string $st
}
$line = $prefix.$line;
- $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
+ $line .= str_repeat(' ', max($this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line), 0));
if ($style) {
$line = sprintf('<%s>%s>', $style, $line);
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_21.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_21.php
new file mode 100644
index 0000000000000..8460e7ececf37
--- /dev/null
+++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_21.php
@@ -0,0 +1,13 @@
+success('Lorem ipsum dolor sit amet');
+ $output->success('Lorem ipsum dolor sit amet with one emoji 🎉');
+ $output->success('Lorem ipsum dolor sit amet with so many of them 👩🌾👩🌾👩🌾👩🌾👩🌾');
+};
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_13.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_13.txt
index 0f3704b7482ea..ea8e4351eafa5 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_13.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_13.txt
@@ -1,7 +1,7 @@
-[39;49m // [39;49mLorem ipsum dolor sit [33mamet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et [39m
-[39;49m // [39;49m[33mdolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea [39m
-[39;49m // [39;49m[33mcommodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla [39m
-[39;49m // [39;49m[33mpariatur.[39m Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim
-[39;49m // [39;49mid est laborum
+[39;49m // [39;49mLorem ipsum dolor sit [33mamet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore [39m
+[39;49m // [39;49m[33mmagna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo [39m
+[39;49m // [39;49m[33mconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla [39m
+[39;49m // [39;49m[33mpariatur.[39m Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
+[39;49m // [39;49mest laborum
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_21.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_21.txt
new file mode 100644
index 0000000000000..aee3c4a89c2e7
--- /dev/null
+++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_21.txt
@@ -0,0 +1,7 @@
+
+ [OK] Lorem ipsum dolor sit amet
+
+ [OK] Lorem ipsum dolor sit amet with one emoji 🎉
+
+ [OK] Lorem ipsum dolor sit amet with so many of them 👩🌾👩🌾👩🌾👩🌾👩🌾
+
diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
index 24c69789c2929..8baf5a6d824cc 100644
--- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
@@ -343,6 +343,31 @@ public function testOverwriteWithSectionOutput()
);
}
+ public function testOverwriteWithAnsiSectionOutput()
+ {
+ // output has 43 visible characters plus 2 invisible ANSI characters
+ putenv('COLUMNS=43');
+ $sections = [];
+ $stream = $this->getOutputStream(true);
+ $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
+
+ $bar = new ProgressBar($output, 50, 0);
+ $bar->setFormat(" \033[44;37m%current%/%max%\033[0m [%bar%] %percent:3s%%");
+ $bar->start();
+ $bar->display();
+ $bar->advance();
+ $bar->advance();
+
+ rewind($output->getStream());
+ $this->assertSame(
+ " \033[44;37m 0/50\033[0m [>---------------------------] 0%".\PHP_EOL.
+ "\x1b[1A\x1b[0J"." \033[44;37m 1/50\033[0m [>---------------------------] 2%".\PHP_EOL.
+ "\x1b[1A\x1b[0J"." \033[44;37m 2/50\033[0m [=>--------------------------] 4%".\PHP_EOL,
+ stream_get_contents($output->getStream())
+ );
+ putenv('COLUMNS=120');
+ }
+
public function testOverwriteMultipleProgressBarsWithSectionOutputs()
{
$sections = [];
@@ -372,6 +397,34 @@ public function testOverwriteMultipleProgressBarsWithSectionOutputs()
);
}
+ public function testOverwriteWithSectionOutputWithNewlinesInMessage()
+ {
+ $sections = [];
+ $stream = $this->getOutputStream(true);
+ $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
+
+ ProgressBar::setFormatDefinition('test', '%current%/%max% [%bar%] %percent:3s%% %message% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.');
+
+ $bar = new ProgressBar($output, 50, 0);
+ $bar->setFormat('test');
+ $bar->start();
+ $bar->display();
+ $bar->setMessage("Twas brillig, and the slithy toves. Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe.\nBeware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!");
+ $bar->advance();
+ $bar->setMessage("He took his vorpal sword in hand; Long time the manxome foe he sought— So rested he by the Tumtum tree And stood awhile in thought.\nAnd, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came!");
+ $bar->advance();
+
+ rewind($output->getStream());
+ $this->assertEquals(
+ ' 0/50 [>] 0% %message% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'.\PHP_EOL.
+ "\x1b[6A\x1b[0J 1/50 [>] 2% Twas brillig, and the slithy toves. Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe.
+Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch! Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.".\PHP_EOL.
+ "\x1b[6A\x1b[0J 2/50 [>] 4% He took his vorpal sword in hand; Long time the manxome foe he sought— So rested he by the Tumtum tree And stood awhile in thought.
+And, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.".\PHP_EOL,
+ stream_get_contents($output->getStream())
+ );
+ }
+
public function testMultipleSectionsWithCustomFormat()
{
$sections = [];
diff --git a/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php
index f3eedb3a2d57f..5777c44b7269a 100644
--- a/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php
+++ b/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php
@@ -162,10 +162,10 @@ public function provideInvalidInput()
public function testToString()
{
$input = new ArrayInput(['-f' => null, '-b' => 'bar', '--foo' => 'b a z', '--lala' => null, 'test' => 'Foo', 'test2' => "A\nB'C"]);
- $this->assertEquals('-f -b=bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input);
+ $this->assertEquals('-f -b bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input);
$input = new ArrayInput(['-b' => ['bval_1', 'bval_2'], '--f' => ['fval_1', 'fval_2']]);
- $this->assertSame('-b=bval_1 -b=bval_2 --f=fval_1 --f=fval_2', (string) $input);
+ $this->assertSame('-b bval_1 -b bval_2 --f=fval_1 --f=fval_2', (string) $input);
$input = new ArrayInput(['array_arg' => ['val_1', 'val_2']]);
$this->assertSame('val_1 val_2', (string) $input);
diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
index a941b2d3eb77c..4fe4839179af6 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
@@ -416,7 +416,7 @@ private function parseDefinition(string $id, $service, string $file, array $defa
trigger_deprecation('symfony/dependency-injection', '5.1', 'Not setting the attribute "version" of the "deprecated" option in "%s" is deprecated.', $file);
}
- $alias->setDeprecated($deprecation['package'] ?? '', $deprecation['version'] ?? '', $deprecation['message']);
+ $alias->setDeprecated($deprecation['package'] ?? '', $deprecation['version'] ?? '', $deprecation['message'] ?? '');
}
}
@@ -485,7 +485,7 @@ private function parseDefinition(string $id, $service, string $file, array $defa
trigger_deprecation('symfony/dependency-injection', '5.1', 'Not setting the attribute "version" of the "deprecated" option in "%s" is deprecated.', $file);
}
- $definition->setDeprecated($deprecation['package'] ?? '', $deprecation['version'] ?? '', $deprecation['message']);
+ $definition->setDeprecated($deprecation['package'] ?? '', $deprecation['version'] ?? '', $deprecation['message'] ?? '');
}
if (isset($service['factory'])) {
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/deprecated_definition_without_message.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/deprecated_definition_without_message.yml
new file mode 100644
index 0000000000000..7fe725fa608ff
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/deprecated_definition_without_message.yml
@@ -0,0 +1,12 @@
+services:
+ service_without_deprecation_message:
+ class: Foo
+ deprecated:
+ package: vendor/package
+ version: 1.1
+
+ alias_without_deprecation_message:
+ alias: foobar
+ deprecated:
+ package: vendor/package
+ version: 1.1
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
index 1a1dc9444a5f7..8591b9f12891a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
@@ -220,6 +220,27 @@ public function testLoadShortSyntax()
$this->assertSame(['$a' => 'a', 'App\Foo' => 'foo'], $services['bar_foo']->getArguments());
}
+ public function testLoadDeprecatedDefinitionWithoutMessageKey()
+ {
+ $container = new ContainerBuilder();
+ $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
+ $loader->load('deprecated_definition_without_message.yml');
+
+ $this->assertTrue($container->getDefinition('service_without_deprecation_message')->isDeprecated());
+ $deprecation = $container->getDefinition('service_without_deprecation_message')->getDeprecation('service_without_deprecation_message');
+ $message = 'The "service_without_deprecation_message" service is deprecated. You should stop using it, as it will be removed in the future.';
+ $this->assertSame($message, $deprecation['message']);
+ $this->assertSame('vendor/package', $deprecation['package']);
+ $this->assertSame('1.1', $deprecation['version']);
+
+ $this->assertTrue($container->getAlias('alias_without_deprecation_message')->isDeprecated());
+ $deprecation = $container->getAlias('alias_without_deprecation_message')->getDeprecation('alias_without_deprecation_message');
+ $message = 'The "alias_without_deprecation_message" service alias is deprecated. You should stop using it, as it will be removed in the future.';
+ $this->assertSame($message, $deprecation['message']);
+ $this->assertSame('vendor/package', $deprecation['package']);
+ $this->assertSame('1.1', $deprecation['version']);
+ }
+
public function testDeprecatedAliases()
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
index 09643dcb70ab9..2850293096659 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
@@ -352,7 +352,7 @@ private function include(string $name, array $context = []): string
extract($context, \EXTR_SKIP);
ob_start();
- include file_exists($name) ? $name : __DIR__.'/../Resources/'.$name;
+ include is_file(\dirname(__DIR__).'/Resources/'.$name) ? \dirname(__DIR__).'/Resources/'.$name : $name;
return trim(ob_get_clean());
}
diff --git a/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
index 10cc5c56bf357..817c48d823357 100644
--- a/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
+++ b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
@@ -24,17 +24,40 @@
*/
class FlattenException
{
+ /** @var string */
private $message;
+
+ /** @var int|string */
private $code;
+
+ /** @var self|null */
private $previous;
+
+ /** @var array */
private $trace;
+
+ /** @var string */
private $traceAsString;
+
+ /** @var string */
private $class;
+
+ /** @var int */
private $statusCode;
+
+ /** @var string */
private $statusText;
+
+ /** @var array */
private $headers;
+
+ /** @var string */
private $file;
+
+ /** @var int */
private $line;
+
+ /** @var string|null */
private $asString;
/**
@@ -108,6 +131,8 @@ public function getStatusCode(): int
}
/**
+ * @param int $code
+ *
* @return $this
*/
public function setStatusCode($code): self
@@ -138,6 +163,8 @@ public function getClass(): string
}
/**
+ * @param string $class
+ *
* @return $this
*/
public function setClass($class): self
@@ -153,6 +180,8 @@ public function getFile(): string
}
/**
+ * @param string $file
+ *
* @return $this
*/
public function setFile($file): self
@@ -168,6 +197,8 @@ public function getLine(): int
}
/**
+ * @param int $line
+ *
* @return $this
*/
public function setLine($line): self
@@ -195,6 +226,8 @@ public function getMessage(): string
}
/**
+ * @param string $message
+ *
* @return $this
*/
public function setMessage($message): self
@@ -219,6 +252,8 @@ public function getCode()
}
/**
+ * @param int|string $code
+ *
* @return $this
*/
public function setCode($code): self
@@ -273,6 +308,10 @@ public function setTraceFromThrowable(\Throwable $throwable): self
}
/**
+ * @param array $trace
+ * @param string|null $file
+ * @param int|null $line
+ *
* @return $this
*/
public function setTrace($trace, $file, $line): self
diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
index f8b150f56434f..4a1350de0b725 100644
--- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
+++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
@@ -1741,7 +1741,7 @@ public function testDumpKeepsExistingPermissionsWhenOverwritingAnExistingFile()
file_put_contents($filename, 'FOO BAR');
chmod($filename, 0745);
- $this->filesystem->dumpFile($filename, 'bar', null);
+ $this->filesystem->dumpFile($filename, 'bar');
$this->assertFilePermissions(745, $filename);
}
@@ -1762,7 +1762,7 @@ public function testCopyShouldKeepExecutionPermission()
}
/**
- * Normalize the given path (transform each blackslash into a real directory separator).
+ * Normalize the given path (transform each forward slash into a real directory separator).
*/
private function normalize(string $path): string
{
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
index 501c26db6bde3..5dd5b498c6896 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
@@ -130,6 +130,10 @@ public function reverseTransform($value)
} elseif ($timestamp > 253402214400) {
// This timestamp represents UTC midnight of 9999-12-31 to prevent 5+ digit years
throw new TransformationFailedException('Years beyond 9999 are not supported.');
+ } elseif (false === $timestamp) {
+ // the value couldn't be parsed but the Intl extension didn't report an error code, this
+ // could be the case when the Intl polyfill is used which always returns 0 as the error code
+ throw new TransformationFailedException(sprintf('"%s" could not be parsed as a date.', $value));
}
try {
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
index 9325a1aa66c25..3af9809ed1f97 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
@@ -24,12 +24,13 @@ class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransfo
/**
* Constructs a transformer.
*
- * @param bool $grouping Whether thousands should be grouped
- * @param int $roundingMode One of the ROUND_ constants in this class
+ * @param bool $grouping Whether thousands should be grouped
+ * @param int $roundingMode One of the ROUND_ constants in this class
+ * @param string|null $locale locale used for transforming
*/
- public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN)
+ public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN, ?string $locale = null)
{
- parent::__construct(0, $grouping, $roundingMode);
+ parent::__construct(0, $grouping, $roundingMode, $locale);
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index eaea6651dc325..fc30dd57e3f0e 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -159,6 +159,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
$knownValues[$child->getName()] = $value;
unset($unknownValues[$value]);
continue;
+ } else {
+ $knownValues[$child->getName()] = null;
}
}
} else {
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php b/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
index 27e3224d70c28..a1cd058a94834 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
@@ -26,7 +26,7 @@ class IntegerType extends AbstractType
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
- $builder->addViewTransformer(new IntegerToLocalizedStringTransformer($options['grouping'], $options['rounding_mode']));
+ $builder->addViewTransformer(new IntegerToLocalizedStringTransformer($options['grouping'], $options['rounding_mode'], !$options['grouping'] ? 'en' : null));
}
/**
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.nn.xlf b/src/Symfony/Component/Form/Resources/translations/validators.nn.xlf
index 2f5da23444d0b..9fac1bf34e34f 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.nn.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.nn.xlf
@@ -4,7 +4,7 @@
This form should not contain extra fields.
- Feltgruppa må ikkje innehalde ekstra felt.
+ Feltgruppa kan ikkje innehalde ekstra felt.
The uploaded file was too large. Please try to upload a smaller file.
@@ -14,6 +14,126 @@
The CSRF token is invalid.
CSRF-nøkkelen er ikkje gyldig.
+
+ This value is not a valid HTML5 color.
+ Verdien er ikkje ein gyldig HTML5-farge.
+
+
+ Please enter a valid birthdate.
+ Gje opp ein gyldig fødselsdato.
+
+
+ The selected choice is invalid.
+ Valget du gjorde er ikkje gyldig.
+
+
+ The collection is invalid.
+ Samlinga er ikkje gyldig.
+
+
+ Please select a valid color.
+ Gje opp ein gyldig farge.
+
+
+ Please select a valid country.
+ Gje opp eit gyldig land.
+
+
+ Please select a valid currency.
+ Gje opp ein gyldig valuta.
+
+
+ Please choose a valid date interval.
+ Gje opp eit gyldig datointervall.
+
+
+ Please enter a valid date and time.
+ Gje opp ein gyldig dato og tid.
+
+
+ Please enter a valid date.
+ Gje opp ein gyldig dato.
+
+
+ Please select a valid file.
+ Velg ei gyldig fil.
+
+
+ The hidden field is invalid.
+ Det skjulte feltet er ikkje gyldig.
+
+
+ Please enter an integer.
+ Gje opp eit heiltal.
+
+
+ Please select a valid language.
+ Gje opp eit gyldig språk.
+
+
+ Please select a valid locale.
+ Gje opp eit gyldig locale.
+
+
+ Please enter a valid money amount.
+ Gje opp ein gyldig sum pengar.
+
+
+ Please enter a number.
+ Gje opp eit nummer.
+
+
+ The password is invalid.
+ Passordet er ikkje gyldig.
+
+
+ Please enter a percentage value.
+ Gje opp ein prosentverdi.
+
+
+ The values do not match.
+ Verdiane er ikkje eins.
+
+
+ Please enter a valid time.
+ Gje opp ei gyldig tid.
+
+
+ Please select a valid timezone.
+ Gje opp ei gyldig tidssone.
+
+
+ Please enter a valid URL.
+ Gje opp ein gyldig URL.
+
+
+ Please enter a valid search term.
+ Gje opp gyldige søkjeord.
+
+
+ Please provide a valid phone number.
+ Gje opp eit gyldig telefonnummer.
+
+
+ The checkbox has an invalid value.
+ Sjekkboksen har ein ugyldig verdi.
+
+
+ Please enter a valid email address.
+ Gje opp ei gyldig e-postadresse.
+
+
+ Please select a valid option.
+ Velg eit gyldig vilkår.
+
+
+ Please select a valid range.
+ Velg eit gyldig spenn.
+
+
+ Please enter a valid week.
+ Gje opp ei gyldig veke.
+
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
index 3eeee26a7e9d7..b09665084dd6e 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
@@ -1321,6 +1321,20 @@ public function testSubmitSingleExpandedObjectChoices()
$this->assertNull($form[4]->getViewData());
}
+ public function testSubmitSingleExpandedClearMissingFalse()
+ {
+ $form = $this->factory->create(self::TESTED_TYPE, 'foo', [
+ 'choices' => [
+ 'foo label' => 'foo',
+ 'bar label' => 'bar',
+ ],
+ 'expanded' => true,
+ ]);
+ $form->submit('bar', false);
+
+ $this->assertSame('bar', $form->getData());
+ }
+
public function testSubmitMultipleExpanded()
{
$form = $this->factory->create(static::TESTED_TYPE, null, [
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php
index a88eb70c5fe7a..15cf308d990dd 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php
@@ -17,13 +17,48 @@ class IntegerTypeTest extends BaseTypeTest
{
public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\IntegerType';
+ private $previousLocale;
+
protected function setUp(): void
{
IntlTestHelper::requireIntl($this, false);
-
+ $this->previousLocale = \Locale::getDefault();
parent::setUp();
}
+ protected function tearDown(): void
+ {
+ \Locale::setDefault($this->previousLocale);
+ }
+
+ /**
+ * @requires extension intl
+ */
+ public function testArabicLocale()
+ {
+ \Locale::setDefault('ar');
+
+ $form = $this->factory->create(static::TESTED_TYPE);
+ $form->submit('123456');
+
+ $this->assertSame(123456, $form->getData());
+ $this->assertSame('123456', $form->getViewData());
+ }
+
+ /**
+ * @requires extension intl
+ */
+ public function testArabicLocaleNonHtml5()
+ {
+ \Locale::setDefault('ar');
+
+ $form = $this->factory->create(static::TESTED_TYPE, null, ['grouping' => true]);
+ $form->submit('123456');
+
+ $this->assertSame(123456, $form->getData());
+ $this->assertSame('١٢٣٬٤٥٦', $form->getViewData());
+ }
+
public function testSubmitRejectsFloats()
{
$form = $this->factory->create(static::TESTED_TYPE);
diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
index 6f583361f20fe..1c17d8274ab08 100644
--- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
@@ -149,7 +149,7 @@ private function open(): void
// Send request and follow redirects when needed
$this->handle = $h = fopen($url, 'r', false, $this->context);
- self::addResponseHeaders($http_response_header, $this->info, $this->headers, $this->info['debug']);
+ self::addResponseHeaders(stream_get_meta_data($h)['wrapper_data'], $this->info, $this->headers, $this->info['debug']);
$url = $resolver($this->multi, $this->headers['location'][0] ?? null, $this->context);
if (null === $url) {
diff --git a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php
index 988ec53bd9edb..2134e6275af56 100644
--- a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php
+++ b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php
@@ -289,7 +289,7 @@ public function stream_stat(): array
'uid' => 0,
'gid' => 0,
'rdev' => 0,
- 'size' => (int) ($headers['content-length'][0] ?? 0),
+ 'size' => (int) ($headers['content-length'][0] ?? -1),
'atime' => 0,
'mtime' => strtotime($headers['last-modified'][0] ?? '') ?: 0,
'ctime' => 0,
diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
index 8c0b7aa330cad..d5296e1fbc552 100644
--- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
+++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
@@ -75,6 +75,19 @@ public function testToStream()
$this->assertTrue(feof($stream));
}
+ public function testStreamCopyToStream()
+ {
+ $client = $this->getHttpClient(__FUNCTION__);
+ $response = $client->request('GET', 'http://localhost:8057');
+ $h = fopen('php://temp', 'w+');
+ stream_copy_to_stream($response->toStream(), $h);
+
+ $this->assertTrue(rewind($h));
+ $this->assertSame("{\n \"SER", fread($h, 10));
+ $this->assertSame('VER_PROTOCOL', fread($h, 12));
+ $this->assertFalse(feof($h));
+ }
+
public function testToStream404()
{
$client = $this->getHttpClient(__FUNCTION__);
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php
index bc334e1d81af1..12c38153a26f4 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php
@@ -42,10 +42,17 @@ public function setKernel(KernelInterface $kernel = null)
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
+ $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
+ $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
+
$this->data = [
'token' => $response->headers->get('X-Debug-Token'),
'symfony_version' => Kernel::VERSION,
- 'symfony_state' => 'unknown',
+ 'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),
+ 'symfony_lts' => 4 === Kernel::MINOR_VERSION,
+ 'symfony_state' => $this->determineSymfonyState(),
+ 'symfony_eom' => $eom->format('F Y'),
+ 'symfony_eol' => $eol->format('F Y'),
'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',
'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',
'php_version' => \PHP_VERSION,
@@ -63,14 +70,6 @@ public function collect(Request $request, Response $response, \Throwable $except
foreach ($this->kernel->getBundles() as $name => $bundle) {
$this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
}
-
- $this->data['symfony_state'] = $this->determineSymfonyState();
- $this->data['symfony_minor_version'] = sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION);
- $this->data['symfony_lts'] = 4 === Kernel::MINOR_VERSION;
- $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
- $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
- $this->data['symfony_eom'] = $eom->format('F Y');
- $this->data['symfony_eol'] = $eol->format('F Y');
}
if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {
@@ -220,7 +219,7 @@ public function getEnv()
/**
* Returns true if the debug is enabled.
*
- * @return bool true if debug is enabled, false otherwise
+ * @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set
*/
public function isDebug()
{
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php
index f8b5d8aa3ac89..d81919919ff46 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php
@@ -178,6 +178,11 @@ public function __wakeup()
$charset = array_pop($this->data);
$fileLinkFormat = array_pop($this->data);
$this->dataCount = \count($this->data);
+ foreach ($this->data as $dump) {
+ if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) {
+ throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+ }
+ }
self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null);
}
@@ -252,7 +257,7 @@ public function __destruct()
}
}
- private function doDump(DataDumperInterface $dumper, $data, string $name, string $file, int $line)
+ private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line)
{
if ($dumper instanceof CliDumper) {
$contextDumper = function ($name, $file, $line, $fmt) {
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 24573ec5aba7a..7549ae9b21ac6 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -74,11 +74,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private static $freshCache = [];
- public const VERSION = '5.2.5';
- public const VERSION_ID = 50205;
+ public const VERSION = '5.2.6';
+ public const VERSION_ID = 50206;
public const MAJOR_VERSION = 5;
public const MINOR_VERSION = 2;
- public const RELEASE_VERSION = 5;
+ public const RELEASE_VERSION = 6;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '07/2021';
@@ -466,7 +466,7 @@ protected function initializeContainer()
if (!flock($lock, $wouldBlock ? \LOCK_SH : \LOCK_EX)) {
fclose($lock);
$lock = null;
- } elseif (!\is_object($this->container = include $cachePath)) {
+ } elseif (!is_file($cachePath) || !\is_object($this->container = include $cachePath)) {
$this->container = null;
} elseif (!$oldContainer || \get_class($this->container) !== $oldContainer->name) {
flock($lock, \LOCK_UN);
diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php
index d6753cb31b29b..6fb3ba8f761c4 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php
@@ -41,6 +41,41 @@ public function testCollect()
$this->assertSame(\extension_loaded('xdebug'), $c->hasXDebug());
$this->assertSame(\extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), $c->hasZendOpcache());
$this->assertSame(\extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), $c->hasApcu());
+ $this->assertSame(sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), $c->getSymfonyMinorVersion());
+ $this->assertContains($c->getSymfonyState(), ['eol', 'eom', 'dev', 'stable']);
+
+ $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->format('F Y');
+ $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->format('F Y');
+ $this->assertSame($eom, $c->getSymfonyEom());
+ $this->assertSame($eol, $c->getSymfonyEol());
+ }
+
+ public function testCollectWithoutKernel()
+ {
+ $c = new ConfigDataCollector();
+ $c->collect(new Request(), new Response());
+
+ $this->assertSame('n/a', $c->getEnv());
+ $this->assertSame('n/a', $c->isDebug());
+ $this->assertSame('config', $c->getName());
+ $this->assertMatchesRegularExpression('~^'.preg_quote($c->getPhpVersion(), '~').'~', \PHP_VERSION);
+ $this->assertMatchesRegularExpression('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', \PHP_VERSION);
+ $this->assertSame(\PHP_INT_SIZE * 8, $c->getPhpArchitecture());
+ $this->assertSame(class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', $c->getPhpIntlLocale());
+ $this->assertSame(date_default_timezone_get(), $c->getPhpTimezone());
+ $this->assertSame(Kernel::VERSION, $c->getSymfonyVersion());
+ $this->assertSame(4 === Kernel::MINOR_VERSION, $c->isSymfonyLts());
+ $this->assertNull($c->getToken());
+ $this->assertSame(\extension_loaded('xdebug'), $c->hasXDebug());
+ $this->assertSame(\extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), $c->hasZendOpcache());
+ $this->assertSame(\extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), $c->hasApcu());
+ $this->assertSame(sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), $c->getSymfonyMinorVersion());
+ $this->assertContains($c->getSymfonyState(), ['eol', 'eom', 'dev', 'stable']);
+
+ $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->format('F Y');
+ $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->format('F Y');
+ $this->assertSame($eom, $c->getSymfonyEom());
+ $this->assertSame($eol, $c->getSymfonyEol());
}
}
diff --git a/src/Symfony/Component/Inflector/Tests/InflectorTest.php b/src/Symfony/Component/Inflector/Tests/InflectorTest.php
index 946e76f4a2776..d54f4ce8206db 100644
--- a/src/Symfony/Component/Inflector/Tests/InflectorTest.php
+++ b/src/Symfony/Component/Inflector/Tests/InflectorTest.php
@@ -204,6 +204,7 @@ public function pluralizeProvider()
['crisis', 'crises'],
['criteria', 'criterion'],
['cup', 'cups'],
+ ['coupon', 'coupons'],
['data', 'data'],
['day', 'days'],
['disco', 'discos'],
diff --git a/src/Symfony/Component/Inflector/composer.json b/src/Symfony/Component/Inflector/composer.json
index 3f8d1eced1493..1162fa4167f86 100644
--- a/src/Symfony/Component/Inflector/composer.json
+++ b/src/Symfony/Component/Inflector/composer.json
@@ -25,7 +25,7 @@
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1",
- "symfony/string": "~5.1.10|^5.2.1"
+ "symfony/string": "^5.2.6"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Inflector\\": "" },
diff --git a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php
index 744d6a0a3894e..e0f70a278543b 100644
--- a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php
+++ b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php
@@ -43,7 +43,7 @@ public function testCreateStore($connection, string $expectedStoreClass)
public function validConnections()
{
if (class_exists(\Redis::class)) {
- yield [$this->createMock(\Redis::class), RedisStore::class];
+ yield [new \Redis(), RedisStore::class];
}
if (class_exists(RedisProxy::class)) {
yield [$this->createMock(RedisProxy::class), RedisStore::class];
diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php
index 52a7c29f41cb7..5de2bb0199e3e 100644
--- a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php
+++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php
@@ -64,8 +64,8 @@ public function testSend()
$content = json_decode($options['body'], true);
$this->assertSame('Hello!', $content['Content']['Simple']['Subject']['Data']);
- $this->assertSame('Saif Eddin ', $content['Destination']['ToAddresses'][0]);
- $this->assertSame('Fabien ', $content['FromEmailAddress']);
+ $this->assertSame('"Saif Eddin" ', $content['Destination']['ToAddresses'][0]);
+ $this->assertSame('"Fabien" ', $content['FromEmailAddress']);
$this->assertSame('Hello There!', $content['Content']['Simple']['Body']['Text']['Data']);
$this->assertSame('Hello There!', $content['Content']['Simple']['Body']['Html']['Data']);
$this->assertSame(['replyto-1@example.com', 'replyto-2@example.com'], $content['ReplyToAddresses']);
diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiTransportTest.php
index b4dfa191aea0f..e19241d416d4c 100644
--- a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiTransportTest.php
+++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiTransportTest.php
@@ -65,8 +65,8 @@ public function testSend()
parse_str($options['body'], $content);
$this->assertSame('Hello!', $content['Message_Subject_Data']);
- $this->assertSame('Saif Eddin ', $content['Destination_ToAddresses_member'][0]);
- $this->assertSame('Fabien ', $content['Source']);
+ $this->assertSame('"Saif Eddin" ', $content['Destination_ToAddresses_member'][0]);
+ $this->assertSame('"Fabien" ', $content['Source']);
$this->assertSame('Hello There!', $content['Message_Body_Text_Data']);
$this->assertSame('aws-configuration-set-name', $content['ConfigurationSetName']);
diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json b/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json
index 6737d1082bae9..5d2ea6bcb5cdb 100644
--- a/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json
+++ b/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json
@@ -17,11 +17,11 @@
],
"require": {
"php": ">=7.2.5",
+ "async-aws/ses": "^1.0",
"symfony/deprecation-contracts": "^2.1",
- "symfony/mailer": "^4.4.12|^5.1.4"
+ "symfony/mailer": "^4.4.21|^5.2.6"
},
"require-dev": {
- "async-aws/ses": "^1.0",
"symfony/http-client": "^4.4|^5.0"
},
"autoload": {
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php
index 67f0c7b935bc8..1ea96bcd8fa55 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php
@@ -130,8 +130,8 @@ public function testSend()
}
$this->assertStringContainsString('Hello!', $content);
- $this->assertStringContainsString('Saif Eddin ', $content);
- $this->assertStringContainsString('Fabien ', $content);
+ $this->assertStringContainsString('"Saif Eddin" ', $content);
+ $this->assertStringContainsString('"Fabien" ', $content);
$this->assertStringContainsString('Hello There!', $content);
return new MockResponse(json_encode(['id' => 'foobar']), [
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json
index 999a6a5fd7b54..728f11761c3da 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json
+++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json
@@ -17,7 +17,7 @@
],
"require": {
"php": ">=7.2.5",
- "symfony/mailer": "^5.1"
+ "symfony/mailer": "^5.2.6"
},
"require-dev": {
"symfony/http-client": "^4.4|^5.0"
diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php
index 1ac55721b9928..760e5a016810a 100644
--- a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php
+++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php
@@ -76,8 +76,8 @@ public function testSend()
$this->assertStringContainsStringIgnoringCase('X-Postmark-Server-Token: KEY', $options['headers'][1] ?? $options['request_headers'][1]);
$body = json_decode($options['body'], true);
- $this->assertSame('Fabien ', $body['From']);
- $this->assertSame('Saif Eddin ', $body['To']);
+ $this->assertSame('"Fabien" ', $body['From']);
+ $this->assertSame('"Saif Eddin" ', $body['To']);
$this->assertSame('Hello!', $body['Subject']);
$this->assertSame('Hello There!', $body['TextBody']);
diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json b/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json
index 6883a6e0c1a50..4d27122ccafae 100644
--- a/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json
+++ b/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json
@@ -17,7 +17,7 @@
],
"require": {
"php": ">=7.2.5",
- "symfony/mailer": "^5.1"
+ "symfony/mailer": "^5.2.6"
},
"require-dev": {
"symfony/http-client": "^4.4|^5.0"
diff --git a/src/Symfony/Component/Mailer/composer.json b/src/Symfony/Component/Mailer/composer.json
index 673b00167df79..34d864d18d41b 100644
--- a/src/Symfony/Component/Mailer/composer.json
+++ b/src/Symfony/Component/Mailer/composer.json
@@ -20,7 +20,7 @@
"egulias/email-validator": "^2.1.10|^3",
"psr/log": "~1.0",
"symfony/event-dispatcher": "^4.4|^5.0",
- "symfony/mime": "^5.2",
+ "symfony/mime": "^5.2.6",
"symfony/polyfill-php80": "^1.15",
"symfony/service-contracts": "^1.1|^2"
},
diff --git a/src/Symfony/Component/Mime/Address.php b/src/Symfony/Component/Mime/Address.php
index 3ef967dd73231..f317e218e11eb 100644
--- a/src/Symfony/Component/Mime/Address.php
+++ b/src/Symfony/Component/Mime/Address.php
@@ -78,7 +78,16 @@ public function getEncodedAddress(): string
public function toString(): string
{
- return ($n = $this->getName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress();
+ return ($n = $this->getEncodedName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress();
+ }
+
+ public function getEncodedName(): string
+ {
+ if ('' === $this->getName()) {
+ return '';
+ }
+
+ return sprintf('"%s"', preg_replace('/"/u', '\"', $this->getName()));
}
/**
diff --git a/src/Symfony/Component/Mime/Tests/AddressTest.php b/src/Symfony/Component/Mime/Tests/AddressTest.php
index d371d0d0a4ca9..a0f2164b5547b 100644
--- a/src/Symfony/Component/Mime/Tests/AddressTest.php
+++ b/src/Symfony/Component/Mime/Tests/AddressTest.php
@@ -27,7 +27,7 @@ public function testConstructor()
$a = new Address('fabien@symfonï.com', 'Fabien');
$this->assertEquals('Fabien', $a->getName());
$this->assertEquals('fabien@symfonï.com', $a->getAddress());
- $this->assertEquals('Fabien ', $a->toString());
+ $this->assertEquals('"Fabien" ', $a->toString());
$this->assertEquals('fabien@xn--symfon-nwa.com', $a->getEncodedAddress());
}
@@ -170,4 +170,10 @@ public function fromStringProvider()
],
];
}
+
+ public function testEncodeNameIfNameContainsCommas()
+ {
+ $address = new Address('fabien@symfony.com', 'Fabien, "Potencier');
+ $this->assertSame('"Fabien, \"Potencier" ', $address->toString());
+ }
}
diff --git a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php
index 9fdbe474bf3ef..08b588b62cbb6 100644
--- a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php
+++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php
@@ -46,7 +46,7 @@ public function __construct(array $config, StorageInterface $storage, ?LockFacto
public function create(?string $key = null): LimiterInterface
{
- $id = $this->config['id'].$key;
+ $id = $this->config['id'].'-'.$key;
$lock = $this->lockFactory ? $this->lockFactory->createLock($id) : new NoLock();
switch ($this->config['policy']) {
diff --git a/src/Symfony/Component/RateLimiter/Tests/Strategy/FixedWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/FixedWindowLimiterTest.php
similarity index 100%
rename from src/Symfony/Component/RateLimiter/Tests/Strategy/FixedWindowLimiterTest.php
rename to src/Symfony/Component/RateLimiter/Tests/Policy/FixedWindowLimiterTest.php
diff --git a/src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/SlidingWindowLimiterTest.php
similarity index 100%
rename from src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowLimiterTest.php
rename to src/Symfony/Component/RateLimiter/Tests/Policy/SlidingWindowLimiterTest.php
diff --git a/src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/SlidingWindowTest.php
similarity index 100%
rename from src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowTest.php
rename to src/Symfony/Component/RateLimiter/Tests/Policy/SlidingWindowTest.php
diff --git a/src/Symfony/Component/RateLimiter/Tests/Strategy/TokenBucketLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php
similarity index 100%
rename from src/Symfony/Component/RateLimiter/Tests/Strategy/TokenBucketLimiterTest.php
rename to src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterCommaController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterCommaController.php
index 3fdf55f30c373..6ca5aeec66772 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterCommaController.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterCommaController.php
@@ -3,14 +3,13 @@
namespace Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures;
use Symfony\Component\Routing\Tests\Fixtures\Attributes\FooAttributes;
-use Symfony\Component\Security\Core\User\User;
#[FooAttributes(
foo: [
'bar' => ['foo','bar'],
'foo'
],
- class: User::class
+ class: \stdClass::class
)]
class AttributesClassParamAfterCommaController
{
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterParenthesisController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterParenthesisController.php
index 06edcabf6d278..92a6759af65a9 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterParenthesisController.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamAfterParenthesisController.php
@@ -3,10 +3,9 @@
namespace Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures;
use Symfony\Component\Routing\Tests\Fixtures\Attributes\FooAttributes;
-use Symfony\Component\Security\Core\User\User;
#[FooAttributes(
- class: User::class,
+ class: \stdClass::class,
foo: [
'bar' => ['foo','bar'],
'foo'
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterCommaController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterCommaController.php
index 4b47967f139a3..fc07e916d0c74 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterCommaController.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterCommaController.php
@@ -3,9 +3,8 @@
namespace Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures;
use Symfony\Component\Routing\Tests\Fixtures\Attributes\FooAttributes;
-use Symfony\Component\Security\Core\User\User;
-#[FooAttributes(foo: ['bar' => ['foo','bar'],'foo'],class: User::class)]
+#[FooAttributes(foo: ['bar' => ['foo','bar'],'foo'],class: \stdClass::class)]
class AttributesClassParamInlineAfterCommaController
{
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterParenthesisController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterParenthesisController.php
index 876cdc33f73bc..13f2592edcbcf 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterParenthesisController.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineAfterParenthesisController.php
@@ -3,9 +3,8 @@
namespace Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures;
use Symfony\Component\Routing\Tests\Fixtures\Attributes\FooAttributes;
-use Symfony\Component\Security\Core\User\User;
-#[FooAttributes(class: User::class,foo: ['bar' => ['foo','bar'],'foo'])]
+#[FooAttributes(class: \stdClass::class,foo: ['bar' => ['foo','bar'],'foo'])]
class AttributesClassParamInlineAfterParenthesisController
{
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterCommaController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterCommaController.php
index 471efd305aa62..3bca2bc9669d0 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterCommaController.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterCommaController.php
@@ -3,7 +3,6 @@
namespace Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures;
use Symfony\Component\Routing\Tests\Fixtures\Attributes\FooAttributes;
-use Symfony\Component\Security\Core\User\User;
#[FooAttributes(foo: ['bar' => ['foo','bar'],'foo'],class: 'Symfony\Component\Security\Core\User\User')]
class AttributesClassParamInlineQuotedAfterCommaController
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterParenthesisController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterParenthesisController.php
index dc0ea7a82096a..31edf3cef98d6 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterParenthesisController.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterParenthesisController.php
@@ -3,9 +3,8 @@
namespace Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures;
use Symfony\Component\Routing\Tests\Fixtures\Attributes\FooAttributes;
-use Symfony\Component\Security\Core\User\User;
-#[FooAttributes(class: 'Symfony\Component\Security\Core\User\User',foo: ['bar' => ['foo','bar'],'foo'])]
+#[FooAttributes(class: \stdClass::class,foo: ['bar' => ['foo','bar'],'foo'])]
class AttributesClassParamInlineQuotedAfterParenthesisController
{
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.nn.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.nn.xlf
index 27b55e5675cac..89ca44fa88f26 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.nn.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.nn.xlf
@@ -36,7 +36,7 @@
No session available, it either timed out or cookies are not enabled.
- Ingen sesjon tilgjengeleg. Sesjonen er anten ikkje lenger gyldig, eller informasjonskapslar er ikke skrudd på i nettlesaren.
+ Ingen sesjon tilgjengeleg. Sesjonen er anten ikkje lenger gyldig, eller informasjonskapslar er ikkje skrudd på i nettlesaren.
No token could be found.
@@ -56,12 +56,20 @@
Account is disabled.
- Brukarkontoen er deaktivert.
+ Brukarkontoen er sperra.
Account is locked.
Brukarkontoen er sperra.
+
+ Too many failed login attempts, please try again later.
+ For mange innloggingsforsøk har feila, prøv igjen seinare.
+
+
+ Invalid or expired login link.
+ Innloggingslenka er ugyldig eller utgjengen.
+