diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index ac82d7063d..426b55def0 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,20 +1,21 @@
| Q | A
| ------------- | ---
-| Branch? | master for features / 3.4 up to 4.2 for bug fixes
+| Branch? | master for features / 3.4, 4.2 or 4.3 for bug fixes
| Bug fix? | yes/no
-| New feature? | yes/no
+| New feature? | yes/no
| BC breaks? | no
-| Deprecations? | yes/no
+| Deprecations? | yes/no
| Tests pass? | yes
| Fixed tickets | #...
| License | MIT
| Doc PR | symfony/symfony-docs#...
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
index c55a0ccafc..3736d4dc9d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
@@ -159,6 +159,7 @@ EOF
$options['show_hidden'] = $input->getOption('show-hidden');
$options['raw_text'] = $input->getOption('raw');
$options['output'] = $io;
+ $options['is_debug'] = $this->getApplication()->getKernel()->isDebug();
try {
$helper->describe($io, $object, $options);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
index 7ea8e39553..323f9ae250 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
@@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
+use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -347,9 +348,14 @@ class TextDescriptor extends Descriptor
if ($argument instanceof Reference) {
$argumentsInformation[] = sprintf('Service(%s)', (string) $argument);
} elseif ($argument instanceof IteratorArgument) {
- $argumentsInformation[] = sprintf('Iterator (%d element(s))', \count($argument->getValues()));
- foreach (array_map(function (Reference $value) {return (string) $value; }, $argument->getValues()) as $service) {
- $argumentsInformation[] = sprintf('- %s', $service);
+ if ($argument instanceof TaggedIteratorArgument) {
+ $argumentsInformation[] = sprintf('Tagged Iterator for "%s"%s', $argument->getTag(), $options['is_debug'] ? '' : sprintf(' (%d element(s))', \count($argument->getValues())));
+ } else {
+ $argumentsInformation[] = sprintf('Iterator (%d element(s))', \count($argument->getValues()));
+ }
+
+ foreach ($argument->getValues() as $ref) {
+ $argumentsInformation[] = sprintf('- Service(%s)', $ref);
}
} elseif ($argument instanceof ServiceLocatorArgument) {
$argumentsInformation[] = sprintf('Service locator (%d element(s))', \count($argument->getValues()));
@@ -357,11 +363,6 @@ class TextDescriptor extends Descriptor
$argumentsInformation[] = 'Inlined Service';
} else {
$argumentsInformation[] = \is_array($argument) ? sprintf('Array (%d element(s))', \count($argument)) : $argument;
- if (\is_array($argument)) {
- foreach (array_keys($argument) as $service) {
- $argumentsInformation[] = sprintf('- %s', $service);
- }
- }
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml
index 8a4846c94e..eafb9b9232 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml
@@ -98,7 +98,7 @@
-
+
%serializer.mapping.cache.file%
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php
index 33b0cb6375..83792e28da 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php
@@ -217,6 +217,7 @@ abstract class AbstractDescriptorTest extends TestCase
private function assertDescription($expectedDescription, $describedObject, array $options = [])
{
+ $options['is_debug'] = false;
$options['raw_output'] = true;
$options['raw_text'] = true;
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt
index 1551f96f57..2e9dc9771c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt
@@ -17,11 +17,8 @@
[39;49m [39;49m[39;49m%parameter%[39;49m[39;49m [39;49m
[39;49m [39;49m[39;49mInlined Service[39;49m[39;49m [39;49m
[39;49m [39;49m[39;49mArray (3 element(s))[39;49m[39;49m [39;49m
-[39;49m [39;49m[39;49m- 0[39;49m[39;49m [39;49m
-[39;49m [39;49m[39;49m- 1[39;49m[39;49m [39;49m
-[39;49m [39;49m[39;49m- 2[39;49m[39;49m [39;49m
[39;49m [39;49m[39;49mIterator (2 element(s))[39;49m[39;49m [39;49m
-[39;49m [39;49m[39;49m- definition_1[39;49m[39;49m [39;49m
-[39;49m [39;49m- .definition_2
+[39;49m [39;49m[39;49m- Service(definition_1)[39;49m[39;49m [39;49m
+[39;49m [39;49m- Service(.definition_2)
---------------- -----------------------------
diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json
index f9b5e18381..098cdadee0 100644
--- a/src/Symfony/Component/Cache/composer.json
+++ b/src/Symfony/Component/Cache/composer.json
@@ -18,7 +18,7 @@
"provide": {
"psr/cache-implementation": "1.0",
"psr/simple-cache-implementation": "1.0",
- "symfony/cache-contracts-implementation": "1.0"
+ "symfony/cache-implementation": "1.0"
},
"require": {
"php": "^7.1.3",
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index 667be07b5a..5a9b185519 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -614,6 +614,15 @@ class Application
$this->init();
$aliases = [];
+
+ foreach ($this->commands as $command) {
+ foreach ($command->getAliases() as $alias) {
+ if (!$this->has($alias)) {
+ $this->commands[$alias] = $command;
+ }
+ }
+ }
+
$allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index efbe2a81fd..0533bb42e7 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -73,8 +73,8 @@ class ApplicationTest extends TestCase
require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
require_once self::$fixturesPath.'/FooWithoutAliasCommand.php';
- require_once self::$fixturesPath.'/TestTiti.php';
- require_once self::$fixturesPath.'/TestToto.php';
+ require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering.php';
+ require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering2.php';
}
protected function normalizeLineBreaks($text)
@@ -165,6 +165,28 @@ class ApplicationTest extends TestCase
$this->assertEquals('foo', $command->getName(), '->register() registers a new command');
}
+ public function testRegisterAmbiguous()
+ {
+ $code = function (InputInterface $input, OutputInterface $output) {
+ $output->writeln('It works!');
+ };
+
+ $application = new Application();
+ $application->setAutoExit(false);
+ $application
+ ->register('test-foo')
+ ->setAliases(['test'])
+ ->setCode($code);
+
+ $application
+ ->register('test-bar')
+ ->setCode($code);
+
+ $tester = new ApplicationTester($application);
+ $tester->run(['test']);
+ $this->assertContains('It works!', $tester->getDisplay(true));
+ }
+
public function testAdd()
{
$application = new Application();
@@ -304,9 +326,9 @@ class ApplicationTest extends TestCase
public function testFindNonAmbiguous()
{
$application = new Application();
- $application->add(new \TestTiti());
- $application->add(new \TestToto());
- $this->assertEquals('test-toto', $application->find('test')->getName());
+ $application->add(new \TestAmbiguousCommandRegistering());
+ $application->add(new \TestAmbiguousCommandRegistering2());
+ $this->assertEquals('test-ambiguous', $application->find('test')->getName());
}
/**
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/TestToto.php b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering.php
similarity index 65%
rename from src/Symfony/Component/Console/Tests/Fixtures/TestToto.php
rename to src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering.php
index 2e6a819593..bece09fcdd 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/TestToto.php
+++ b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering.php
@@ -4,19 +4,19 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-class TestToto extends Command
+class TestAmbiguousCommandRegistering extends Command
{
protected function configure()
{
$this
- ->setName('test-toto')
- ->setDescription('The test-toto command')
+ ->setName('test-ambiguous')
+ ->setDescription('The test-ambiguous command')
->setAliases(['test'])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
- $output->write('test-toto');
+ $output->write('test-ambiguous');
}
}
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/TestTiti.php b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering2.php
similarity index 62%
rename from src/Symfony/Component/Console/Tests/Fixtures/TestTiti.php
rename to src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering2.php
index 72e29d2a0a..9dde486245 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/TestTiti.php
+++ b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering2.php
@@ -4,18 +4,18 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-class TestTiti extends Command
+class TestAmbiguousCommandRegistering2 extends Command
{
protected function configure()
{
$this
- ->setName('test-titi')
- ->setDescription('The test:titi command')
+ ->setName('test-ambiguous2')
+ ->setDescription('The test-ambiguous2 command')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
- $output->write('test-titi');
+ $output->write('test-ambiguous2');
}
}
diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json
index 94a729df8d..282b52ed1f 100644
--- a/src/Symfony/Component/DependencyInjection/composer.json
+++ b/src/Symfony/Component/DependencyInjection/composer.json
@@ -40,7 +40,7 @@
},
"provide": {
"psr/container-implementation": "1.0",
- "symfony/service-contracts-implementation": "1.0"
+ "symfony/service-implementation": "1.0"
},
"autoload": {
"psr-4": { "Symfony\\Component\\DependencyInjection\\": "" },
diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json
index 0469bb41dd..b02ae3beea 100644
--- a/src/Symfony/Component/HttpClient/composer.json
+++ b/src/Symfony/Component/HttpClient/composer.json
@@ -16,7 +16,7 @@
],
"provide": {
"psr/http-client-implementation": "1.0",
- "symfony/http-client-contracts-implementation": "1.1"
+ "symfony/http-client-implementation": "1.1"
},
"require": {
"php": "^7.1.3",
diff --git a/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php b/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php
new file mode 100644
index 0000000000..a937e85b54
--- /dev/null
+++ b/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Intl\Data\Generator;
+
+use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
+use Symfony\Component\Intl\Locale;
+
+/**
+ * @author Roland Franssen
+ *
+ * @internal
+ */
+trait FallbackTrait
+{
+ private $fallbackCache = [];
+ private $generatingFallback = false;
+
+ /**
+ * @param string $tempDir
+ * @param string $displayLocale
+ *
+ * @return array|null
+ *
+ * @see AbstractDataGenerator::generateDataForLocale()
+ */
+ abstract protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale);
+
+ /**
+ * @param string $tempDir
+ *
+ * @return array|null
+ *
+ * @see AbstractDataGenerator::generateDataForRoot()
+ */
+ abstract protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir);
+
+ private function generateFallbackData(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): array
+ {
+ if (null === $fallback = Locale::getFallback($displayLocale)) {
+ return [];
+ }
+
+ if (isset($this->fallbackCache[$fallback])) {
+ return $this->fallbackCache[$fallback];
+ }
+
+ $prevGeneratingFallback = $this->generatingFallback;
+ $this->generatingFallback = true;
+
+ try {
+ $data = 'root' === $fallback ? $this->generateDataForRoot($reader, $tempDir) : $this->generateDataForLocale($reader, $tempDir, $fallback);
+ } finally {
+ $this->generatingFallback = $prevGeneratingFallback;
+ }
+
+ return $this->fallbackCache[$fallback] = $data ?: [];
+ }
+}
diff --git a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php
index b0455c7e8b..9d57b07069 100644
--- a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php
+++ b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php
@@ -16,7 +16,6 @@ use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
use Symfony\Component\Intl\Exception\MissingResourceException;
-use Symfony\Component\Intl\Locale;
/**
* The rule for compiling the locale bundle.
@@ -28,11 +27,11 @@ use Symfony\Component\Intl\Locale;
*/
class LocaleDataGenerator extends AbstractDataGenerator
{
- private $locales;
- private $localeAliases;
- private $localeParents;
- private $fallbackMapping;
- private $fallbackCache = [];
+ use FallbackTrait;
+
+ private $locales = [];
+ private $localeAliases = [];
+ private $localeParents = [];
/**
* {@inheritdoc}
@@ -42,7 +41,6 @@ class LocaleDataGenerator extends AbstractDataGenerator
$this->locales = $scanner->scanLocales($sourceDir.'/locales');
$this->localeAliases = $scanner->scanAliases($sourceDir.'/locales');
$this->localeParents = $scanner->scanParents($sourceDir.'/locales');
- $this->fallbackMapping = $this->generateFallbackMapping(array_diff($this->locales, array_keys($this->localeAliases)), $this->localeAliases);
return $this->locales;
}
@@ -66,8 +64,6 @@ class LocaleDataGenerator extends AbstractDataGenerator
*/
protected function preGenerate()
{
- $this->fallbackCache = [];
-
// Write parents locale file for the Translation component
\file_put_contents(
__DIR__.'/../../../Translation/Resources/data/parents.json',
@@ -81,7 +77,8 @@ class LocaleDataGenerator extends AbstractDataGenerator
protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale)
{
// Don't generate aliases, as they are resolved during runtime
- if (isset($this->localeAliases[$displayLocale])) {
+ // Unless an alias is needed as fallback for de-duplication purposes
+ if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) {
return;
}
@@ -93,7 +90,7 @@ class LocaleDataGenerator extends AbstractDataGenerator
$localeNames = [];
foreach ($this->locales as $locale) {
// Ensure a normalized list of pure locales
- if (isset($this->localeAliases[$displayLocale]) || \Locale::getAllVariants($locale)) {
+ if (\Locale::getAllVariants($locale)) {
continue;
}
@@ -110,21 +107,27 @@ class LocaleDataGenerator extends AbstractDataGenerator
}
}
- // Process again to de-duplicate locales and their fallback locales
- // Only keep the differences
- $fallback = $displayLocale;
- while (isset($this->fallbackMapping[$fallback])) {
- if (!isset($this->fallbackCache[$fallback = $this->fallbackMapping[$fallback]])) {
- $this->fallbackCache[$fallback] = $this->generateDataForLocale($reader, $tempDir, $fallback) ?: [];
- }
- if (isset($this->fallbackCache[$fallback]['Names'])) {
- $localeNames = array_diff($localeNames, $this->fallbackCache[$fallback]['Names']);
- }
+ $data = [
+ 'Names' => $localeNames,
+ ];
+
+ // Don't de-duplicate a fallback locale
+ // Ensures the display locale can be de-duplicated on itself
+ if ($this->generatingFallback) {
+ return $data;
}
- if ($localeNames) {
- return ['Names' => $localeNames];
+ // Process again to de-duplicate locale and its fallback locales
+ // Only keep the differences
+ $fallbackData = $this->generateFallbackData($reader, $tempDir, $displayLocale);
+ if (isset($fallbackData['Names'])) {
+ $data['Names'] = array_diff($data['Names'], $fallbackData['Names']);
}
+ if (!$data['Names']) {
+ return;
+ }
+
+ return $data;
}
/**
@@ -139,12 +142,10 @@ class LocaleDataGenerator extends AbstractDataGenerator
*/
protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir)
{
- if ($this->locales || $this->localeAliases) {
- return [
- 'Locales' => $this->locales,
- 'Aliases' => $this->localeAliases,
- ];
- }
+ return [
+ 'Locales' => $this->locales,
+ 'Aliases' => $this->localeAliases,
+ ];
}
/**
@@ -183,30 +184,4 @@ class LocaleDataGenerator extends AbstractDataGenerator
return $name;
}
-
- private function generateFallbackMapping(array $displayLocales, array $aliases)
- {
- $displayLocales = array_flip($displayLocales);
- $mapping = [];
-
- foreach ($displayLocales as $displayLocale => $_) {
- $mapping[$displayLocale] = null;
- $fallback = $displayLocale;
-
- // Recursively search for a fallback locale until one is found
- while (null !== ($fallback = Locale::getFallback($fallback))) {
- // Currently, no locale has an alias as fallback locale.
- // If this starts to be the case, we need to add code here.
- \assert(!isset($aliases[$fallback]));
-
- // Check whether the fallback exists
- if (isset($displayLocales[$fallback])) {
- $mapping[$displayLocale] = $fallback;
- break;
- }
- }
- }
-
- return $mapping;
- }
}
diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php b/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php
index b5584c5867..0528a7b213 100644
--- a/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php
+++ b/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php
@@ -42,7 +42,7 @@ trait CompiledUrlMatcherTrait
throw new MethodNotAllowedException(array_keys($allow));
}
if (!$this instanceof RedirectableUrlMatcherInterface) {
- throw new ResourceNotFoundException();
+ throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
}
if (!\in_array($this->context->getMethod(), ['HEAD', 'GET'], true)) {
// no-op
@@ -67,7 +67,7 @@ trait CompiledUrlMatcherTrait
}
}
- throw new ResourceNotFoundException();
+ throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
}
private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array
@@ -110,10 +110,8 @@ trait CompiledUrlMatcherTrait
}
$hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
- if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
- if ($hasRequiredScheme) {
- $allow += $requiredMethods;
- }
+ if ($hasRequiredScheme && $requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
+ $allow += $requiredMethods;
continue;
}
@@ -162,15 +160,13 @@ trait CompiledUrlMatcherTrait
}
}
- $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
- if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
- if ($hasRequiredScheme) {
- $allow += $requiredMethods;
- }
+ if ($requiredSchemes && !isset($requiredSchemes[$context->getScheme()])) {
+ $allowSchemes += $requiredSchemes;
continue;
}
- if (!$hasRequiredScheme) {
- $allowSchemes += $requiredSchemes;
+
+ if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
+ $allow += $requiredMethods;
continue;
}
diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
index 7b2662a2a3..dca1d6366f 100644
--- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
+++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
@@ -89,7 +89,7 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
return $ret;
}
- if ('/' === $pathinfo && !$this->allow) {
+ if ('/' === $pathinfo && !$this->allow && !$this->allowSchemes) {
throw new NoConfigurationException();
}
@@ -182,24 +182,16 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
if ($supportsTrailingSlash && (!$requiredMethods || \in_array('GET', $requiredMethods))) {
return $this->allow = $this->allowSchemes = [];
}
-
continue;
}
- $hasRequiredScheme = !$route->getSchemes() || $route->hasScheme($this->context->getScheme());
- if ($requiredMethods) {
- if (!\in_array($method, $requiredMethods)) {
- if ($hasRequiredScheme) {
- $this->allow = array_merge($this->allow, $requiredMethods);
- }
-
- continue;
- }
+ if ($route->getSchemes() && !$route->hasScheme($this->context->getScheme())) {
+ $this->allowSchemes = array_merge($this->allowSchemes, $route->getSchemes());
+ continue;
}
- if (!$hasRequiredScheme) {
- $this->allowSchemes = array_merge($this->allowSchemes, $route->getSchemes());
-
+ if ($requiredMethods && !\in_array($method, $requiredMethods)) {
+ $this->allow = array_merge($this->allow, $requiredMethods);
continue;
}
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
index e4c199d579..b7fb28e8fc 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
@@ -747,6 +747,7 @@ class UrlMatcherTest extends TestCase
/**
* @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
+ * @expectedExceptionMessage No routes found for "/".
*/
public function testSchemeAndMethodMismatch()
{
diff --git a/src/Symfony/Component/Translation/composer.json b/src/Symfony/Component/Translation/composer.json
index d8664944ec..2b1b6d84da 100644
--- a/src/Symfony/Component/Translation/composer.json
+++ b/src/Symfony/Component/Translation/composer.json
@@ -37,7 +37,7 @@
"symfony/yaml": "<3.4"
},
"provide": {
- "symfony/translation-contracts-implementation": "1.0"
+ "symfony/translation-implementation": "1.0"
},
"suggest": {
"symfony/config": "",
diff --git a/src/Symfony/Contracts/README.md b/src/Symfony/Contracts/README.md
index d9cfd2c225..66a465f226 100644
--- a/src/Symfony/Contracts/README.md
+++ b/src/Symfony/Contracts/README.md
@@ -16,8 +16,8 @@ Design Principles
* they must be backward compatible with existing Symfony components.
Packages that implement specific contracts should list them in the "provide"
-section of their "composer.json" file, using the `symfony/*-contracts-implementation`
-convention (e.g. `"provide": { "symfony/cache-contracts-implementation": "1.0" }`).
+section of their "composer.json" file, using the `symfony/*-implementation`
+convention (e.g. `"provide": { "symfony/cache-implementation": "1.0" }`).
FAQ
---
diff --git a/src/Symfony/Contracts/composer.json b/src/Symfony/Contracts/composer.json
index b83e7c0535..0011480949 100644
--- a/src/Symfony/Contracts/composer.json
+++ b/src/Symfony/Contracts/composer.json
@@ -26,11 +26,11 @@
"suggest": {
"psr/cache": "When using the Cache contracts",
"psr/container": "When using the Service contracts",
- "symfony/cache-contracts-implementation": "",
+ "symfony/cache-implementation": "",
"symfony/event-dispatcher-implementation": "",
- "symfony/http-client-contracts-implementation": "",
- "symfony/service-contracts-implementation": "",
- "symfony/translation-contracts-implementation": ""
+ "symfony/http-client-implementation": "",
+ "symfony/service-implementation": "",
+ "symfony/translation-implementation": ""
},
"autoload": {
"psr-4": { "Symfony\\Contracts\\": "" },