diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php
index b17cc0a44f9e..1f5f472802e7 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php
@@ -118,6 +118,39 @@ public function testWritesResponseEvenIfXContentDigestIsPresent()
$this->assertNotNull($response);
}
+ public function testWritingARestoredResponseDoesNotCorruptCache()
+ {
+ /*
+ * This covers the regression reported in https://github.com/symfony/symfony/issues/37174.
+ *
+ * A restored response does *not* load the body, but only keep the file path in a special X-Body-File
+ * header. For reasons (?), the file path was also used as the restored response body.
+ * It would be up to others (HttpCache...?) to honor this header and actually load the response content
+ * from there.
+ *
+ * When a restored response was stored again, the Store itself would ignore the header. In the first
+ * step, this would compute a new Content Digest based on the file path in the restored response body;
+ * this is covered by "Checkpoint 1" below. But, since the X-Body-File header was left untouched (Checkpoint 2), downstream
+ * code (HttpCache...) would not immediately notice.
+ *
+ * Only upon performing the lookup for a second time, we'd get a Response where the (wrong) Content Digest
+ * is also reflected in the X-Body-File header, this time also producing wrong content when the downstream
+ * evaluates it.
+ */
+ $this->store->write($this->request, $this->response);
+ $digest = $this->response->headers->get('X-Content-Digest');
+ $path = $this->getStorePath($digest);
+
+ $response = $this->store->lookup($this->request);
+ $this->store->write($this->request, $response);
+ $this->assertEquals($digest, $response->headers->get('X-Content-Digest')); // Checkpoint 1
+ $this->assertEquals($path, $response->headers->get('X-Body-File')); // Checkpoint 2
+
+ $response = $this->store->lookup($this->request);
+ $this->assertEquals($digest, $response->headers->get('X-Content-Digest'));
+ $this->assertEquals($path, $response->headers->get('X-Body-File'));
+ }
+
public function testFindsAStoredEntryWithLookup()
{
$this->storeSimpleEntry();
diff --git a/src/Symfony/Component/Ldap/Security/LdapUserProvider.php b/src/Symfony/Component/Ldap/Security/LdapUserProvider.php
index e8965c070b00..c7216e716618 100644
--- a/src/Symfony/Component/Ldap/Security/LdapUserProvider.php
+++ b/src/Symfony/Component/Ldap/Security/LdapUserProvider.php
@@ -108,7 +108,7 @@ public function refreshUser(UserInterface $user)
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
}
- return new LdapUser($user->getEntry(), $user->getUsername(), $user->getPassword(), $user->getRoles());
+ return new LdapUser($user->getEntry(), $user->getUsername(), $user->getPassword(), $user->getRoles(), $user->getExtraFields());
}
/**
diff --git a/src/Symfony/Component/Ldap/Tests/Security/LdapUserProviderTest.php b/src/Symfony/Component/Ldap/Tests/Security/LdapUserProviderTest.php
index 8d0a7a351758..a2e888077cde 100644
--- a/src/Symfony/Component/Ldap/Tests/Security/LdapUserProviderTest.php
+++ b/src/Symfony/Component/Ldap/Tests/Security/LdapUserProviderTest.php
@@ -330,4 +330,14 @@ public function testLoadUserByUsernameIsSuccessfulWithPasswordAttribute()
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com', null, null, [], 'sAMAccountName', '({uid_key}={username})', 'userpassword', ['email']);
$this->assertInstanceOf(LdapUser::class, $provider->loadUserByUsername('foo'));
}
+
+ public function testRefreshUserShouldReturnUserWithSameProperties()
+ {
+ $ldap = $this->createMock(LdapInterface::class);
+ $provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com', null, null, [], 'sAMAccountName', '({uid_key}={username})', 'userpassword', ['email']);
+
+ $user = new LdapUser(new Entry('foo'), 'foo', 'bar', ['ROLE_DUMMY'], ['email' => 'foo@symfony.com']);
+
+ $this->assertEquals($user, $provider->refreshUser($user));
+ }
}
diff --git a/src/Symfony/Component/Lock/Store/PdoStore.php b/src/Symfony/Component/Lock/Store/PdoStore.php
index 00d4ad4d3657..6a116d3c236f 100644
--- a/src/Symfony/Component/Lock/Store/PdoStore.php
+++ b/src/Symfony/Component/Lock/Store/PdoStore.php
@@ -13,6 +13,7 @@
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\Lock\Exception\InvalidArgumentException;
@@ -158,10 +159,10 @@ public function putOffExpiration(Key $key, float $ttl)
$stmt->bindValue(':id', $this->getHashedKey($key));
$stmt->bindValue(':token1', $uniqueToken);
$stmt->bindValue(':token2', $uniqueToken);
- $stmt->execute();
+ $result = $stmt->execute();
// If this method is called twice in the same second, the row wouldn't be updated. We have to call exists to know if we are the owner
- if (!$stmt->rowCount() && !$this->exists($key)) {
+ if (!($result instanceof Result ? $result : $stmt)->rowCount() && !$this->exists($key)) {
throw new LockConflictedException();
}
@@ -191,9 +192,9 @@ public function exists(Key $key)
$stmt->bindValue(':id', $this->getHashedKey($key));
$stmt->bindValue(':token', $this->getUniqueToken($key));
- $stmt->execute();
+ $result = $stmt->execute();
- return (bool) (method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn());
+ return (bool) ($result instanceof Result ? $result->fetchOne() : $stmt->fetchColumn());
}
/**
diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php
index 7295fdf79a5a..0bd5627ac9bd 100644
--- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php
@@ -113,6 +113,9 @@ private function getPayload(Email $email, Envelope $envelope): array
if ($email->getHtmlBody()) {
$payload['Message.Body.Html.Data'] = $email->getHtmlBody();
}
+ if ($email->getReplyTo()) {
+ $payload['ReplyToAddresses.member'] = $this->stringifyAddresses($email->getReplyTo());
+ }
return $payload;
}
diff --git a/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php b/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php
index 0472c36b6209..b06ac839c64f 100644
--- a/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php
+++ b/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php
@@ -22,9 +22,6 @@ class SendEmailMessage
private $message;
private $envelope;
- /**
- * @internal
- */
public function __construct(RawMessage $message, Envelope $envelope = null)
{
$this->message = $message;
diff --git a/src/Symfony/Component/Mailer/Tests/TransportTest.php b/src/Symfony/Component/Mailer/Tests/TransportTest.php
index 95eb5b6ebf03..dfd8d1926e61 100644
--- a/src/Symfony/Component/Mailer/Tests/TransportTest.php
+++ b/src/Symfony/Component/Mailer/Tests/TransportTest.php
@@ -60,6 +60,22 @@ public function fromStringProvider(): iterable
];
}
+ /**
+ * @dataProvider fromDsnProvider
+ */
+ public function testFromDsn(string $dsn, TransportInterface $transport): void
+ {
+ $this->assertEquals($transport, Transport::fromDsn($dsn));
+ }
+
+ public function fromDsnProvider(): iterable
+ {
+ yield 'multiple transports' => [
+ 'failover(smtp://a smtp://b)',
+ new FailoverTransport([new Transport\Smtp\EsmtpTransport('a'), new Transport\Smtp\EsmtpTransport('b')]),
+ ];
+ }
+
/**
* @dataProvider fromWrongStringProvider
*/
diff --git a/src/Symfony/Component/Mailer/Transport.php b/src/Symfony/Component/Mailer/Transport.php
index a8f159dc7c49..c0cd0c5fb9da 100644
--- a/src/Symfony/Component/Mailer/Transport.php
+++ b/src/Symfony/Component/Mailer/Transport.php
@@ -51,7 +51,7 @@ class Transport
public static function fromDsn(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
{
- $factory = new self(self::getDefaultFactories($dispatcher, $client, $logger));
+ $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger)));
return $factory->fromString($dsn);
}
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
index d34e45d2ce51..b4348d4958a4 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
@@ -11,14 +11,14 @@
namespace Symfony\Component\Messenger\Tests\Transport\Doctrine;
+use Doctrine\DBAL\Abstraction\Result;
use Doctrine\DBAL\DBALException;
-use Doctrine\DBAL\Driver\ResultStatement;
-use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SchemaConfig;
use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer;
+use Doctrine\DBAL\Statement;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
use Symfony\Component\Messenger\Transport\Doctrine\Connection;
@@ -30,7 +30,7 @@ public function testGetAMessageWillChangeItsStatus()
$queryBuilder = $this->getQueryBuilderMock();
$driverConnection = $this->getDBALConnectionMock();
$schemaSynchronizer = $this->getSchemaSynchronizerMock();
- $stmt = $this->getStatementMock([
+ $stmt = $this->getResultMock([
'id' => 1,
'body' => '{"message":"Hi"}',
'headers' => json_encode(['type' => DummyMessage::class]),
@@ -64,7 +64,7 @@ public function testGetWithNoPendingMessageWillReturnNull()
$queryBuilder = $this->getQueryBuilderMock();
$driverConnection = $this->getDBALConnectionMock();
$schemaSynchronizer = $this->getSchemaSynchronizerMock();
- $stmt = $this->getStatementMock(false);
+ $stmt = $this->getResultMock(false);
$queryBuilder
->method('getParameters')
@@ -143,16 +143,12 @@ private function getQueryBuilderMock()
return $queryBuilder;
}
- private function getStatementMock($expectedResult): ResultStatement
+ private function getResultMock($expectedResult)
{
- $mockedInterface = interface_exists(ForwardCompatibleResultStatement::class)
- ? ForwardCompatibleResultStatement::class
- : ResultStatement::class;
-
- $stmt = $this->createMock($mockedInterface);
+ $stmt = $this->createMock(interface_exists(Result::class) ? Result::class : Statement::class);
$stmt->expects($this->once())
- ->method(method_exists($mockedInterface, 'fetchAssociative') ? 'fetchAssociative' : 'fetch')
+ ->method(interface_exists(Result::class) ? 'fetchAssociative' : 'fetch')
->willReturn($expectedResult);
return $stmt;
@@ -267,7 +263,7 @@ public function testFind()
$driverConnection = $this->getDBALConnectionMock();
$schemaSynchronizer = $this->getSchemaSynchronizerMock();
$id = 1;
- $stmt = $this->getStatementMock([
+ $stmt = $this->getResultMock([
'id' => $id,
'body' => '{"message":"Hi"}',
'headers' => json_encode(['type' => DummyMessage::class]),
@@ -312,12 +308,9 @@ public function testFindAll()
'headers' => json_encode(['type' => DummyMessage::class]),
];
- $mockedInterface = interface_exists(ForwardCompatibleResultStatement::class)
- ? ForwardCompatibleResultStatement::class
- : ResultStatement::class;
- $stmt = $this->createMock($mockedInterface);
+ $stmt = $this->createMock(interface_exists(Result::class) ? Result::class : Statement::class);
$stmt->expects($this->once())
- ->method(method_exists($mockedInterface, 'fetchAllAssociative') ? 'fetchAllAssociative' : 'fetchAll')
+ ->method(interface_exists(Result::class) ? 'fetchAllAssociative' : 'fetchAll')
->willReturn([$message1, $message2]);
$driverConnection
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
index 45ca64b77106..37a38b95d485 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\Messenger\Tests\Transport\Doctrine;
+use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Version;
use PHPUnit\Framework\TestCase;
@@ -71,7 +72,7 @@ public function testSendWithDelay()
->setParameter(':body', '{"message": "Hi i am delayed"}')
->execute();
- $available_at = new \DateTime(method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn());
+ $available_at = new \DateTime($stmt instanceof Result ? $stmt->fetchOne() : $stmt->fetchColumn());
$now = new \DateTime();
$now->modify('+60 seconds');
diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
index 4f5b43c4ac8d..19141bd8d94c 100644
--- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
@@ -13,7 +13,7 @@
use Doctrine\DBAL\Connection as DBALConnection;
use Doctrine\DBAL\DBALException;
-use Doctrine\DBAL\Driver\ResultStatement;
+use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\DBAL\Schema\Schema;
@@ -164,7 +164,7 @@ public function get(): ?array
$query->getParameters(),
$query->getParameterTypes()
);
- $doctrineEnvelope = method_exists($stmt, 'fetchAssociative') ? $stmt->fetchAssociative() : $stmt->fetch();
+ $doctrineEnvelope = $stmt instanceof Result ? $stmt->fetchAssociative() : $stmt->fetch();
if (false === $doctrineEnvelope) {
$this->driverConnection->commit();
@@ -252,7 +252,7 @@ public function getMessageCount(): int
$stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes());
- return method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn();
+ return $stmt instanceof Result ? $stmt->fetchOne() : $stmt->fetchColumn();
}
public function findAll(int $limit = null): array
@@ -263,7 +263,7 @@ public function findAll(int $limit = null): array
}
$stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes());
- $data = method_exists($stmt, 'fetchAllAssociative') ? $stmt->fetchAllAssociative() : $stmt->fetchAll();
+ $data = $stmt instanceof Result ? $stmt->fetchAllAssociative() : $stmt->fetchAll();
return array_map(function ($doctrineEnvelope) {
return $this->decodeEnvelopeHeaders($doctrineEnvelope);
@@ -276,7 +276,7 @@ public function find($id): ?array
->where('m.id = ?');
$stmt = $this->executeQuery($queryBuilder->getSQL(), [$id]);
- $data = method_exists($stmt, 'fetchAssociative') ? $stmt->fetchAssociative() : $stmt->fetch();
+ $data = $stmt instanceof Result ? $stmt->fetchAssociative() : $stmt->fetch();
return false === $data ? null : $this->decodeEnvelopeHeaders($data);
}
@@ -310,7 +310,7 @@ private function createQueryBuilder(): QueryBuilder
->from($this->configuration['table_name'], 'm');
}
- private function executeQuery(string $sql, array $parameters = [], array $types = []): ResultStatement
+ private function executeQuery(string $sql, array $parameters = [], array $types = [])
{
try {
$stmt = $this->driverConnection->executeQuery($sql, $parameters, $types);
diff --git a/src/Symfony/Component/Mime/Address.php b/src/Symfony/Component/Mime/Address.php
index b0dcbd0880f6..53f682c9c2bb 100644
--- a/src/Symfony/Component/Mime/Address.php
+++ b/src/Symfony/Component/Mime/Address.php
@@ -89,7 +89,7 @@ public static function create($address): self
return $address;
}
if (\is_string($address)) {
- return new self($address);
+ return self::fromString($address);
}
throw new InvalidArgumentException(sprintf('An address can be an instance of Address or a string ("%s") given).', \is_object($address) ? \get_class($address) : \gettype($address)));
diff --git a/src/Symfony/Component/Mime/Crypto/SMimeSigner.php b/src/Symfony/Component/Mime/Crypto/SMimeSigner.php
index 243aaf10da06..1b555375ce90 100644
--- a/src/Symfony/Component/Mime/Crypto/SMimeSigner.php
+++ b/src/Symfony/Component/Mime/Crypto/SMimeSigner.php
@@ -24,11 +24,6 @@ final class SMimeSigner extends SMime
private $signOptions;
private $extraCerts;
- /**
- * @var string|null
- */
- private $privateKeyPassphrase;
-
/**
* @param string $certificate The path of the file containing the signing certificate (in PEM format)
* @param string $privateKey The path of the file containing the private key (in PEM format)
@@ -52,7 +47,6 @@ public function __construct(string $certificate, string $privateKey, string $pri
$this->signOptions = $signOptions ?? PKCS7_DETACHED;
$this->extraCerts = $extraCerts ? realpath($extraCerts) : null;
- $this->privateKeyPassphrase = $privateKeyPassphrase;
}
public function sign(Message $message): Message
diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php
index 1db4d70a301f..a7897d905610 100644
--- a/src/Symfony/Component/Serializer/Serializer.php
+++ b/src/Symfony/Component/Serializer/Serializer.php
@@ -21,6 +21,7 @@
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
+use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
@@ -151,7 +152,7 @@ public function normalize($data, string $format = null, array $context = [])
}
if (\is_array($data) || $data instanceof \Traversable) {
- if ($data instanceof \Countable && 0 === $data->count()) {
+ if (($context[AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS] ?? false) === true && $data instanceof \Countable && 0 === $data->count()) {
return $data;
}
diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php
index ce4754d15057..c855cc5b8460 100644
--- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php
@@ -489,6 +489,27 @@ public function testNotNormalizableValueExceptionMessageForAResource()
(new Serializer())->normalize(tmpfile());
}
+ public function testNormalizeTransformEmptyArrayObjectToArray()
+ {
+ $serializer = new Serializer(
+ [
+ new PropertyNormalizer(),
+ new ObjectNormalizer(),
+ new ArrayDenormalizer(),
+ ],
+ [
+ 'json' => new JsonEncoder(),
+ ]
+ );
+
+ $object = [];
+ $object['foo'] = new \ArrayObject();
+ $object['bar'] = new \ArrayObject(['notempty']);
+ $object['baz'] = new \ArrayObject(['nested' => new \ArrayObject()]);
+
+ $this->assertSame('{"foo":[],"bar":["notempty"],"baz":{"nested":[]}}', $serializer->serialize($object, 'json'));
+ }
+
public function testNormalizePreserveEmptyArrayObject()
{
$serializer = new Serializer(
diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php
index 55dfc1276366..fcb1d146944a 100644
--- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php
+++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php
@@ -92,7 +92,7 @@ public function testExport(string $testName, $value, bool $staticValueExpected =
} elseif (\PHP_VERSION_ID < 70400) {
$fixtureFile = __DIR__.'/Fixtures/'.$testName.'-legacy.php';
} else {
- $this->markAsSkipped('PHP >= 7.4.6 required.');
+ $this->markTestSkipped('PHP >= 7.4.6 required.');
}
$this->assertStringEqualsFile($fixtureFile, $dump);
diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
index 8ef46a9a90ee..c1ad3ffec501 100644
--- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
+++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
@@ -786,6 +786,30 @@ public function testUncheckedTimeoutThrows()
}
}
+ public function testTimeoutWithActiveConcurrentStream()
+ {
+ $p1 = TestHttpServer::start(8067);
+ $p2 = TestHttpServer::start(8077);
+
+ $client = $this->getHttpClient(__FUNCTION__);
+ $streamingResponse = $client->request('GET', 'http://localhost:8067/max-duration');
+ $blockingResponse = $client->request('GET', 'http://localhost:8077/timeout-body', [
+ 'timeout' => 0.25,
+ ]);
+
+ $this->assertSame(200, $streamingResponse->getStatusCode());
+ $this->assertSame(200, $blockingResponse->getStatusCode());
+
+ $this->expectException(TransportExceptionInterface::class);
+
+ try {
+ $blockingResponse->getContent();
+ } finally {
+ $p1->stop();
+ $p2->stop();
+ }
+ }
+
public function testDestruct()
{
$client = $this->getHttpClient(__FUNCTION__);
diff --git a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php
index cfc100d80ce6..06a11444e35e 100644
--- a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php
+++ b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php
@@ -19,23 +19,28 @@
*/
class TestHttpServer
{
- private static $process;
+ private static $process = [];
- public static function start()
+ public static function start(int $port = 8057)
{
- if (self::$process) {
- self::$process->stop();
+ if (isset(self::$process[$port])) {
+ self::$process[$port]->stop();
+ } else {
+ register_shutdown_function(static function () use ($port) {
+ self::$process[$port]->stop();
+ });
}
$finder = new PhpExecutableFinder();
- $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:8057']));
+ $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port]));
$process->setWorkingDirectory(__DIR__.'/Fixtures/web');
$process->start();
+ self::$process[$port] = $process;
do {
usleep(50000);
- } while (!@fopen('http://127.0.0.1:8057/', 'r'));
+ } while (!@fopen('http://127.0.0.1:'.$port, 'r'));
- self::$process = $process;
+ return $process;
}
}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy