diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 57c1517854..859515b3ca 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -11,7 +11,7 @@
Replace this notice by a short README for your feature/bugfix. This will help people
understand your PR and can be used as a start for the documentation.
-Additionally (see https://symfony.com/roadmap):
+Additionally (see https://symfony.com/releases):
- Always add tests and ensure they pass.
- Never break backward compatibility (see https://symfony.com/bc).
- Bug fixes must be submitted against the lowest maintained branch where they apply
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig
index c085303213..4e4a59d1b3 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig
@@ -153,7 +153,7 @@
{{ collector.symfonyeom }}
{{ collector.symfonyeol }}
- View roadmap
+ View roadmap
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index c1fd41b80b..c39007ad73 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -647,7 +647,15 @@ class Application implements ResetInterface
// filter out aliases for commands which are already on the list
if (\count($commands) > 1) {
$commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
- $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
+
+ if (isset($commandList[$name])) {
+ return $this->get($name);
+ }
+
+ foreach ($commands as $k => $nameOrAlias) {
+ if ($nameOrAlias === $name) {
+ return $this->get($nameOrAlias);
+ }
if (!$commandList[$nameOrAlias] instanceof Command) {
$commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
}
@@ -656,8 +664,14 @@ class Application implements ResetInterface
$aliases[$nameOrAlias] = $commandName;
- return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
- }));
+ if ($commandName === $nameOrAlias || !\in_array($commandName, $commands)) {
+ continue;
+ }
+
+ unset($commands[$k]);
+ }
+
+ $commands = array_unique($commands);
}
if (\count($commands) > 1) {
diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php
index 0a641103d8..5aefa3d7b9 100644
--- a/src/Symfony/Component/Console/Helper/Table.php
+++ b/src/Symfony/Component/Console/Helper/Table.php
@@ -589,7 +589,9 @@ class Table
++$numberOfRows; // Add row for header separator
}
- ++$numberOfRows; // Add row for footer separator
+ if (\count($this->rows) > 0) {
+ ++$numberOfRows; // Add row for footer separator
+ }
return $numberOfRows;
}
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index df8d8e46fe..cd8904ea72 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -1692,6 +1692,31 @@ class ApplicationTest extends TestCase
$this->assertArrayNotHasKey('disabled', $application->all());
}
+ public function testFindAlternativesDoesNotLoadSameNamespaceCommandsOnExactMatch()
+ {
+ $application = new Application();
+ $application->setAutoExit(false);
+
+ $loaded = [];
+
+ $application->setCommandLoader(new FactoryCommandLoader([
+ 'foo:bar' => function () use (&$loaded) {
+ $loaded['foo:bar'] = true;
+
+ return (new Command('foo:bar'))->setCode(function () {});
+ },
+ 'foo' => function () use (&$loaded) {
+ $loaded['foo'] = true;
+
+ return (new Command('foo'))->setCode(function () {});
+ },
+ ]));
+
+ $application->run(new ArrayInput(['command' => 'foo']), new NullOutput());
+
+ $this->assertSame(['foo' => true], $loaded);
+ }
+
protected function getDispatcher($skipCommand = false)
{
$dispatcher = new EventDispatcher();
diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php
index 124309dd5b..c4acc3fbff 100644
--- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php
@@ -951,6 +951,38 @@ TABLE;
$table->appendRow(['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25']);
}
+ public function testSectionOutputHandlesZeroRowsAfterRender()
+ {
+ $sections = [];
+ $stream = $this->getOutputStream(true);
+ $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
+ $output->writeln('My Table');
+ $table = new Table($output);
+ $table
+ ->setHeaders(['ISBN', 'Title', 'Author', 'Price'])
+ ->setRows([]);
+
+ $table->render();
+
+ $table->appendRow(['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25']);
+
+ $expected =
+ <<assertEquals($expected, $this->getOutputContent($output));
+ }
+
public function testIsNotDefinedStyleException()
{
$this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException');
diff --git a/src/Symfony/Component/ErrorHandler/Debug.php b/src/Symfony/Component/ErrorHandler/Debug.php
index a3c0511d22..9cc8ec17a8 100644
--- a/src/Symfony/Component/ErrorHandler/Debug.php
+++ b/src/Symfony/Component/ErrorHandler/Debug.php
@@ -29,7 +29,7 @@ class Debug
ini_set('display_errors', 1);
}
- ini_set('zend.assertions', 1);
+ @ini_set('zend.assertions', 1);
ini_set('assert.active', 1);
ini_set('assert.warning', 0);
ini_set('assert.exception', 1);
diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php
index da1c6ab7fd..e1bcea35d2 100644
--- a/src/Symfony/Component/Finder/Finder.php
+++ b/src/Symfony/Component/Finder/Finder.php
@@ -782,6 +782,10 @@ class Finder implements \IteratorAggregate, \Countable
*/
private function normalizeDir(string $dir): string
{
+ if ('/' === $dir) {
+ return $dir;
+ }
+
$dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
index 3facef58a0..7616b14a24 100644
--- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
+++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
@@ -70,7 +70,11 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
}
$subPathname .= $this->getFilename();
- return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
+ if ('/' !== $basePath = $this->rootPath) {
+ $basePath .= $this->directorySeparator;
+ }
+
+ return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php
index 895d110f41..4a331954bd 100644
--- a/src/Symfony/Component/HttpFoundation/Response.php
+++ b/src/Symfony/Component/HttpFoundation/Response.php
@@ -258,10 +258,12 @@ class Response
$this->setContent(null);
$headers->remove('Content-Type');
$headers->remove('Content-Length');
+ // prevent PHP from sending the Content-Type header based on default_mimetype
+ ini_set('default_mimetype', '');
} else {
// Content-type based on the Request
if (!$headers->has('Content-Type')) {
- $format = $request->getPreferredFormat();
+ $format = $request->getPreferredFormat(null);
if (null !== $format && $mimeType = $request->getMimeType($format)) {
$headers->set('Content-Type', $mimeType);
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
index 8139dcceef..6e6a210eee 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
@@ -461,18 +461,10 @@ class ResponseTest extends ResponseTestCase
public function testDefaultContentType()
{
- $headerMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\ResponseHeaderBag')->setMethods(['set'])->getMock();
- $headerMock->expects($this->at(0))
- ->method('set')
- ->with('Content-Type', 'text/html');
- $headerMock->expects($this->at(1))
- ->method('set')
- ->with('Content-Type', 'text/html; charset=UTF-8');
-
$response = new Response('foo');
- $response->headers = $headerMock;
-
$response->prepare(new Request());
+
+ $this->assertSame('text/html; charset=UTF-8', $response->headers->get('Content-Type'));
}
public function testContentTypeCharset()
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf
index 8ee3120482..0702e8dfcd 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf
@@ -366,6 +366,10 @@
This value should be between {{ min }} and {{ max }}.
Dieser Wert sollte zwischen {{ min }} und {{ max }} sein.
+
+ This value is not a valid hostname.
+ Dieser Wert ist kein gültiger Hostname.
+