diff --git a/Controller/RedirectController.php b/Controller/RedirectController.php
index 1001fad63..d1f253166 100644
--- a/Controller/RedirectController.php
+++ b/Controller/RedirectController.php
@@ -115,13 +115,17 @@ public function urlRedirectAction(Request $request, string $path, bool $permanen
$statusCode = $permanent ? 301 : 302;
}
+ $scheme ??= $request->getScheme();
+
+ if (str_starts_with($path, '//')) {
+ $path = $scheme.':'.$path;
+ }
+
// redirect if the path is a full URL
if (parse_url($path, \PHP_URL_SCHEME)) {
return new RedirectResponse($path, $statusCode);
}
- $scheme ??= $request->getScheme();
-
if ($qs = $request->server->get('QUERY_STRING') ?: $request->getQueryString()) {
if (!str_contains($path, '?')) {
$qs = '?'.$qs;
diff --git a/Resources/config/schema/symfony-1.0.xsd b/Resources/config/schema/symfony-1.0.xsd
index d8d23168d..c6816fbd0 100644
--- a/Resources/config/schema/symfony-1.0.xsd
+++ b/Resources/config/schema/symfony-1.0.xsd
@@ -531,7 +531,7 @@
-
+
diff --git a/Test/KernelTestCase.php b/Test/KernelTestCase.php
index 632b782ad..ac798f765 100644
--- a/Test/KernelTestCase.php
+++ b/Test/KernelTestCase.php
@@ -118,6 +118,12 @@ protected static function ensureKernelShutdown()
if (null !== static::$kernel) {
static::$kernel->boot();
$container = static::$kernel->getContainer();
+
+ if ($container->has('services_resetter')) {
+ // Instantiate the service because Container::reset() only resets services that have been used
+ $container->get('services_resetter');
+ }
+
static::$kernel->shutdown();
static::$booted = false;
diff --git a/Tests/Controller/RedirectControllerTest.php b/Tests/Controller/RedirectControllerTest.php
index b2da9ef58..161424e0e 100644
--- a/Tests/Controller/RedirectControllerTest.php
+++ b/Tests/Controller/RedirectControllerTest.php
@@ -183,6 +183,20 @@ public function testFullURLWithMethodKeep()
$this->assertEquals(307, $returnResponse->getStatusCode());
}
+ public function testProtocolRelative()
+ {
+ $request = new Request();
+ $controller = new RedirectController();
+
+ $returnResponse = $controller->urlRedirectAction($request, '//foo.bar/');
+ $this->assertRedirectUrl($returnResponse, 'http://foo.bar/');
+ $this->assertSame(302, $returnResponse->getStatusCode());
+
+ $returnResponse = $controller->urlRedirectAction($request, '//foo.bar/', false, 'https');
+ $this->assertRedirectUrl($returnResponse, 'https://foo.bar/');
+ $this->assertSame(302, $returnResponse->getStatusCode());
+ }
+
public function testUrlRedirectDefaultPorts()
{
$host = 'www.example.com';
diff --git a/Tests/DependencyInjection/Fixtures/php/lock.php b/Tests/DependencyInjection/Fixtures/php/lock.php
new file mode 100644
index 000000000..116e074df
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/lock.php
@@ -0,0 +1,9 @@
+loadFromExtension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'lock' => null,
+]);
diff --git a/Tests/DependencyInjection/Fixtures/php/lock_named.php b/Tests/DependencyInjection/Fixtures/php/lock_named.php
new file mode 100644
index 000000000..de8a8f495
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/lock_named.php
@@ -0,0 +1,16 @@
+setParameter('env(REDIS_DSN)', 'redis://paas.com');
+
+$container->loadFromExtension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'lock' => [
+ 'foo' => 'semaphore',
+ 'bar' => 'flock',
+ 'baz' => ['semaphore', 'flock'],
+ 'qux' => '%env(REDIS_DSN)%',
+ ],
+]);
diff --git a/Tests/DependencyInjection/Fixtures/php/semaphore.php b/Tests/DependencyInjection/Fixtures/php/semaphore.php
new file mode 100644
index 000000000..c2a1e3b6e
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/semaphore.php
@@ -0,0 +1,9 @@
+loadFromExtension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'semaphore' => 'redis://localhost',
+]);
diff --git a/Tests/DependencyInjection/Fixtures/php/semaphore_named.php b/Tests/DependencyInjection/Fixtures/php/semaphore_named.php
new file mode 100644
index 000000000..c42b55983
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/semaphore_named.php
@@ -0,0 +1,14 @@
+setParameter('env(REDIS_DSN)', 'redis://paas.com');
+
+$container->loadFromExtension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'semaphore' => [
+ 'foo' => 'redis://paas.com',
+ 'qux' => '%env(REDIS_DSN)%',
+ ],
+]);
diff --git a/Tests/DependencyInjection/Fixtures/xml/lock.xml b/Tests/DependencyInjection/Fixtures/xml/lock.xml
index 5ddb62f11..2796cb3f9 100644
--- a/Tests/DependencyInjection/Fixtures/xml/lock.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/lock.xml
@@ -8,6 +8,6 @@
-
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/lock_named.xml b/Tests/DependencyInjection/Fixtures/xml/lock_named.xml
index 85cf3cb57..02659713e 100644
--- a/Tests/DependencyInjection/Fixtures/xml/lock_named.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/lock_named.xml
@@ -5,7 +5,6 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
-
redis://paas.com
@@ -18,7 +17,7 @@
flock
semaphore
flock
- %env(REDIS_URL)%
+ %env(REDIS_DSN)%
diff --git a/Tests/DependencyInjection/Fixtures/xml/semaphore.xml b/Tests/DependencyInjection/Fixtures/xml/semaphore.xml
index 7acbe2ced..dcab80326 100644
--- a/Tests/DependencyInjection/Fixtures/xml/semaphore.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/semaphore.xml
@@ -8,6 +8,8 @@
-
+
+ redis://localhost
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/semaphore_named.xml b/Tests/DependencyInjection/Fixtures/xml/semaphore_named.xml
new file mode 100644
index 000000000..7e454c2fd
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/xml/semaphore_named.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ redis://paas.com
+ %env(REDIS_DSN)%
+
+
+
diff --git a/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/Tests/DependencyInjection/FrameworkExtensionTestCase.php
index ef9fc0f20..10ab48e9a 100644
--- a/Tests/DependencyInjection/FrameworkExtensionTestCase.php
+++ b/Tests/DependencyInjection/FrameworkExtensionTestCase.php
@@ -56,6 +56,7 @@
use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
use Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface;
+use Symfony\Component\Lock\Store\SemaphoreStore;
use Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsTransportFactory;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransportFactory;
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransportFactory;
@@ -2386,6 +2387,67 @@ public function testAssetMapperWithoutAssets()
$this->assertFalse($container->has('assets._default_package'));
}
+ public function testDefaultLock()
+ {
+ $container = $this->createContainerFromFile('lock');
+
+ self::assertTrue($container->hasDefinition('lock.default.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('lock.default.factory')->getArgument(0));
+
+ if (class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported()) {
+ self::assertEquals(new Reference('semaphore'), $storeDef->getArgument(0));
+ } else {
+ self::assertEquals(new Reference('flock'), $storeDef->getArgument(0));
+ }
+ }
+
+ public function testNamedLocks()
+ {
+ $container = $this->createContainerFromFile('lock_named');
+
+ self::assertTrue($container->hasDefinition('lock.foo.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('lock.foo.factory')->getArgument(0));
+ self::assertEquals(new Reference('semaphore'), $storeDef->getArgument(0));
+
+ self::assertTrue($container->hasDefinition('lock.bar.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('lock.bar.factory')->getArgument(0));
+ self::assertEquals(new Reference('flock'), $storeDef->getArgument(0));
+
+ self::assertTrue($container->hasDefinition('lock.baz.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('lock.baz.factory')->getArgument(0));
+ self::assertIsArray($storeDefArg = $storeDef->getArgument(0));
+ $storeDef1 = $container->getDefinition($storeDefArg[0]);
+ $storeDef2 = $container->getDefinition($storeDefArg[1]);
+ self::assertEquals(new Reference('semaphore'), $storeDef1->getArgument(0));
+ self::assertEquals(new Reference('flock'), $storeDef2->getArgument(0));
+
+ self::assertTrue($container->hasDefinition('lock.qux.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('lock.qux.factory')->getArgument(0));
+ self::assertStringContainsString('REDIS_DSN', $storeDef->getArgument(0));
+ }
+
+ public function testDefaultSemaphore()
+ {
+ $container = $this->createContainerFromFile('semaphore');
+
+ self::assertTrue($container->hasDefinition('semaphore.default.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('semaphore.default.factory')->getArgument(0));
+ self::assertSame('redis://localhost', $storeDef->getArgument(0));
+ }
+
+ public function testNamedSemaphores()
+ {
+ $container = $this->createContainerFromFile('semaphore_named');
+
+ self::assertTrue($container->hasDefinition('semaphore.foo.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('semaphore.foo.factory')->getArgument(0));
+ self::assertSame('redis://paas.com', $storeDef->getArgument(0));
+
+ self::assertTrue($container->hasDefinition('semaphore.qux.factory'));
+ $storeDef = $container->getDefinition($container->getDefinition('semaphore.qux.factory')->getArgument(0));
+ self::assertStringContainsString('REDIS_DSN', $storeDef->getArgument(0));
+ }
+
protected function createContainer(array $data = [])
{
return new ContainerBuilder(new EnvPlaceholderParameterBag(array_merge([
diff --git a/Tests/Functional/Bundle/TestBundle/TestServiceContainer/ResettableService.php b/Tests/Functional/Bundle/TestBundle/TestServiceContainer/ResettableService.php
new file mode 100644
index 000000000..e723da81e
--- /dev/null
+++ b/Tests/Functional/Bundle/TestBundle/TestServiceContainer/ResettableService.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer;
+
+class ResettableService
+{
+ private $count = 0;
+
+ public function myCustomName(): void
+ {
+ ++$this->count;
+ }
+
+ public function getCount(): int
+ {
+ return $this->count;
+ }
+}
diff --git a/Tests/Functional/Psr4RoutingTest.php b/Tests/Functional/Psr4RoutingTest.php
index 811a99a11..6104a52ce 100644
--- a/Tests/Functional/Psr4RoutingTest.php
+++ b/Tests/Functional/Psr4RoutingTest.php
@@ -11,9 +11,6 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
-/**
- * @requires function Symfony\Component\Routing\Loader\Psr4DirectoryLoader::__construct
- */
final class Psr4RoutingTest extends AbstractAttributeRoutingTestCase
{
protected function getTestCaseApp(): string
diff --git a/Tests/Functional/app/TestServiceContainer/services.yml b/Tests/Functional/app/TestServiceContainer/services.yml
index 46cb7be6a..baeab3f3f 100644
--- a/Tests/Functional/app/TestServiceContainer/services.yml
+++ b/Tests/Functional/app/TestServiceContainer/services.yml
@@ -23,3 +23,8 @@ services:
decorates: decorated
properties:
inner: '@.inner'
+
+ Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\ResettableService:
+ public: true
+ tags:
+ - kernel.reset: { method: 'myCustomName' }
diff --git a/composer.json b/composer.json
index af934f35d..93ddcb0db 100644
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,7 @@
"ext-xml": "*",
"symfony/cache": "^6.4|^7.0",
"symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^7.1",
+ "symfony/dependency-injection": "^7.1.5",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/error-handler": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",