diff --git a/.travis.yml b/.travis.yml index fe993abbd2..e43e311d88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -225,7 +225,7 @@ install: export SYMFONY_DEPRECATIONS_HELPER=weak && cp composer.json composer.json.orig && echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json && - php .github/build-packages.php HEAD^ $(find src/Symfony -mindepth 3 -type f -name composer.json -printf '%h\n' | sort) && + php .github/build-packages.php HEAD^ $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | sort) && mv composer.json composer.json.phpunit && mv composer.json.orig composer.json fi @@ -249,7 +249,7 @@ install: - | # Skip the phpunit-bridge on bugfix-only branches when $deps is empty if [[ ! $deps && ! $TRAVIS_BRANCH = *.x ]]; then - export COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort) + export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort) fi - | diff --git a/phpunit b/phpunit index af8cc7f752..71915eecb2 100755 --- a/phpunit +++ b/phpunit @@ -24,5 +24,8 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION')) { if (!getenv('SYMFONY_PATCH_TYPE_DECLARATIONS')) { putenv('SYMFONY_PATCH_TYPE_DECLARATIONS=deprecations=1'); } +if (getcwd() === realpath(__DIR__.'/src/Symfony/Bridge/PhpUnit')) { + putenv('SYMFONY_DEPRECATIONS_HELPER=disabled'); +} putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit'; diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index c03a4c2962..554851ad8a 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -265,11 +265,11 @@ if (!class_exists('SymfonyExcludeListPhpunit', false)) { if (method_exists('PHPUnit\Util\ExcludeList', 'addDirectory')) { (new PHPUnit\Util\Excludelist())->getExcludedDirectories(); PHPUnit\Util\ExcludeList::addDirectory(\dirname((new \ReflectionClass('SymfonyExcludeListPhpunit'))->getFileName())); - PHPUnit\Util\ExcludeList::addDirectory(\dirname((new \ReflectionClass('SymfonyExcludeListSimplePhpunit'))->getFileName())); + class_exists('SymfonyExcludeListSimplePhpunit', false) && PHPUnit\Util\ExcludeList::addDirectory(\dirname((new \ReflectionClass('SymfonyExcludeListSimplePhpunit'))->getFileName())); } elseif (method_exists('PHPUnit\Util\Blacklist', 'addDirectory')) { (new PHPUnit\Util\BlackList())->getBlacklistedDirectories(); PHPUnit\Util\Blacklist::addDirectory(\dirname((new \ReflectionClass('SymfonyExcludeListPhpunit'))->getFileName())); - PHPUnit\Util\Blacklist::addDirectory(\dirname((new \ReflectionClass('SymfonyExcludeListSimplePhpunit'))->getFileName())); + class_exists('SymfonyExcludeListSimplePhpunit', false) && PHPUnit\Util\Blacklist::addDirectory(\dirname((new \ReflectionClass('SymfonyExcludeListSimplePhpunit'))->getFileName())); } else { PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyExcludeListPhpunit'] = 1; PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyExcludeListSimplePhpunit'] = 1; diff --git a/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php b/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php index e00c8f4845..7a02a96237 100644 --- a/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php +++ b/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php @@ -25,9 +25,9 @@ class DefaultMarshaller implements MarshallerInterface public function __construct(bool $useIgbinarySerialize = null) { if (null === $useIgbinarySerialize) { - $useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.0', phpversion('igbinary'), '<=')); - } elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || (\PHP_VERSION_ID >= 70400 && version_compare('3.1.0', phpversion('igbinary'), '>')))) { - throw new CacheException(\extension_loaded('igbinary') && \PHP_VERSION_ID >= 70400 ? 'Please upgrade the "igbinary" PHP extension to v3.1 or higher.' : 'The "igbinary" PHP extension is not loaded.'); + $useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<=')); + } elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')))) { + throw new CacheException(\extension_loaded('igbinary') && \PHP_VERSION_ID >= 70400 ? 'Please upgrade the "igbinary" PHP extension to v3.1.6 or higher.' : 'The "igbinary" PHP extension is not loaded.'); } $this->useIgbinarySerialize = $useIgbinarySerialize; } @@ -66,7 +66,7 @@ class DefaultMarshaller implements MarshallerInterface return null; } static $igbinaryNull; - if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.0', phpversion('igbinary'), '<=')) ? igbinary_serialize(null) : false)) { + if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) { return null; } $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); diff --git a/src/Symfony/Component/Cache/Tests/Marshaller/DefaultMarshallerTest.php b/src/Symfony/Component/Cache/Tests/Marshaller/DefaultMarshallerTest.php index aaef04610e..050aab4207 100644 --- a/src/Symfony/Component/Cache/Tests/Marshaller/DefaultMarshallerTest.php +++ b/src/Symfony/Component/Cache/Tests/Marshaller/DefaultMarshallerTest.php @@ -24,7 +24,7 @@ class DefaultMarshallerTest extends TestCase 'b' => function () {}, ]; - $expected = ['a' => \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.0', phpversion('igbinary'), '<=')) ? igbinary_serialize(123) : serialize(123)]; + $expected = ['a' => \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<=')) ? igbinary_serialize(123) : serialize(123)]; $this->assertSame($expected, $marshaller->marshall($values, $failed)); $this->assertSame(['b'], $failed); } @@ -43,7 +43,7 @@ class DefaultMarshallerTest extends TestCase */ public function testIgbinaryUnserialize() { - if (\PHP_VERSION_ID >= 70400 && version_compare('3.1.0', phpversion('igbinary'), '>')) { + if (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')) { $this->markTestSkipped('igbinary is not compatible with PHP 7.4.'); } @@ -67,7 +67,7 @@ class DefaultMarshallerTest extends TestCase */ public function testIgbinaryUnserializeNotFoundClass() { - if (\PHP_VERSION_ID >= 70400 && version_compare('3.1.0', phpversion('igbinary'), '>')) { + if (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')) { $this->markTestSkipped('igbinary is not compatible with PHP 7.4.'); } @@ -95,7 +95,7 @@ class DefaultMarshallerTest extends TestCase */ public function testIgbinaryUnserializeInvalid() { - if (\PHP_VERSION_ID >= 70400 && version_compare('3.1.0', phpversion('igbinary'), '>')) { + if (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')) { $this->markTestSkipped('igbinary is not compatible with PHP 7.4.'); } diff --git a/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf b/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf new file mode 100644 index 0000000000..cfe681e3b0 --- /dev/null +++ b/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf @@ -0,0 +1,119 @@ + + + + + + This form should not contain extra fields. + Ovaj obrazac ne bi trebalo da sadrži dodatna polja. + + + The uploaded file was too large. Please try to upload a smaller file. + Prenijeta (uploaded) datoteka je prevelika. Molim pokušajte prenijeti manju datoteku. + + + The CSRF token is invalid. Please try to resubmit the form. + CSRF vrijednost nije ispravna. Molim pokušajte ponovo da pošaljete obrazac. + + + This value is not a valid HTML5 color. + Ova vrijednost nije ispravna HTML5 boja. + + + Please enter a valid birthdate. + Molim upišite ispravan datum rođenja. + + + The selected choice is invalid. + Odabrani izbor nije ispravan. + + + The collection is invalid. + Ova kolekcija nije ispravna. + + + Please select a valid color. + Molim izaberite ispravnu boju. + + + Please select a valid country. + Molim izaberite ispravnu državu. + + + Please select a valid currency. + Molim izaberite ispravnu valutu. + + + Please choose a valid date interval. + Molim izaberite ispravan datumski interval. + + + Please enter a valid date and time. + Molim upišite ispravan datum i vrijeme. + + + Please enter a valid date. + Molim upišite ispravan datum. + + + Please select a valid file. + Molim izaberite ispravnu datoteku. + + + The hidden field is invalid. + Skriveno polje nije ispravno. + + + Please enter an integer. + Molim upišite cijeli broj (integer). + + + Please select a valid language. + Molim izaberite ispravan jezik. + + + Please select a valid locale. + Molim izaberite ispravnu lokalizaciju. + + + Please enter a valid money amount. + Molim upišite ispravnu količinu novca. + + + Please enter a number. + Molim upišite broj. + + + The password is invalid. + Ova lozinka nije ispravna. + + + Please enter a percentage value. + Molim upišite procentualnu vrijednost. + + + The values do not match. + Date vrijednosti se ne poklapaju. + + + Please enter a valid time. + Molim upišite ispravno vrijeme. + + + Please select a valid timezone. + Molim izaberite ispravnu vremensku zonu. + + + Please enter a valid URL. + Molim upišite ispravan URL. + + + Please enter a valid search term. + Molim upišite ispravan termin za pretragu. + + + Please provide a valid phone number. + Molim navedite ispravan broj telefona. + + + + diff --git a/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf index 9ae4d71912..3e79f391ad 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf @@ -14,6 +14,106 @@ The CSRF token is invalid. Please try to resubmit the form. O token CSRF é inválido. Por favor, tente reenviar o formulário. + + This value is not a valid HTML5 color. + Este valor não é uma cor HTML5 válida. + + + Please enter a valid birthdate. + Por favor, informe uma data de nascimento válida. + + + The selected choice is invalid. + A escolha selecionada é inválida. + + + The collection is invalid. + A coleção é inválida. + + + Please select a valid color. + Por favor, selecione uma cor válida. + + + Please select a valid country. + Por favor, selecione um país válido. + + + Please select a valid currency. + Por favor, selecione uma moeda válida. + + + Please choose a valid date interval. + Por favor, escolha um intervalo de datas válido. + + + Please enter a valid date and time. + Por favor, informe uma data e horário válidos. + + + Please enter a valid date. + Por favor, informe uma data válida. + + + Please select a valid file. + Por favor, selecione um arquivo válido. + + + The hidden field is invalid. + O campo oculto é inválido. + + + Please enter an integer. + Por favor, informe um número inteiro. + + + Please select a valid language. + Por favor, selecione um idioma válido. + + + Please select a valid locale. + Por favor, selecione uma configuração de local válida. + + + Please enter a valid money amount. + Por favor, informe um valor monetário válido. + + + Please enter a number. + Por favor, informe um número. + + + The password is invalid. + A senha é inválida. + + + Please enter a percentage value. + Por favor, informe um valor percentual. + + + The values do not match. + Os valores não conferem. + + + Please enter a valid time. + Por favor, informe um horário válido. + + + Please select a valid timezone. + Por favor, selecione um fuso horário válido. + + + Please enter a valid URL. + Por favor, informe uma URL válida. + + + Please enter a valid search term. + Por favor, informe um termo de busca válido. + + + Please provide a valid phone number. + Por favor, informe um telefone válido. + diff --git a/src/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf b/src/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf index ff7f550adf..1aa242f418 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf @@ -12,7 +12,107 @@ The CSRF token is invalid. Please try to resubmit the form. - CSRF вредност је невалидна. Покушајте поново. + CSRF вредност није исправна. Покушајте поново. + + + This value is not a valid HTML5 color. + Ова вредност није исправна HTML5 боја. + + + Please enter a valid birthdate. + Молим упишите исправан датум рођења. + + + The selected choice is invalid. + Одабрани избор није исправан. + + + The collection is invalid. + Ова колекција није исправна. + + + Please select a valid color. + Молим изаберите исправну боју. + + + Please select a valid country. + Молим изаберите исправну државу. + + + Please select a valid currency. + Молим изаберите исправну валуту. + + + Please choose a valid date interval. + Молим изаберите исправан датумски интервал. + + + Please enter a valid date and time. + Молим упишите исправан датум и време. + + + Please enter a valid date. + Молим упишите исправан датум. + + + Please select a valid file. + Молим изаберите исправну датотеку. + + + The hidden field is invalid. + Скривено поље није исправно. + + + Please enter an integer. + Молим упишите цео број (integer). + + + Please select a valid language. + Молим изаберите исправан језик. + + + Please select a valid locale. + Молим изаберите исправну локализацију. + + + Please enter a valid money amount. + Молим упишите исправну количину новца. + + + Please enter a number. + Молим упишите број. + + + The password is invalid. + Ова лозинка није исправна. + + + Please enter a percentage value. + Молим упишите процентуалну вредност. + + + The values do not match. + Дате вредности се не поклапају. + + + Please enter a valid time. + Молим упишите исправно време. + + + Please select a valid timezone. + Молим изаберите исправну временску зону. + + + Please enter a valid URL. + Молим упишите исправан URL. + + + Please enter a valid search term. + Молим упишите исправан термин за претрагу. + + + Please provide a valid phone number. + Молим наведите исправан број телефона. diff --git a/src/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf index 6c4be35857..75a2aaab70 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf @@ -12,7 +12,107 @@ The CSRF token is invalid. Please try to resubmit the form. - CSRF vrednost je nevalidna. Pokušajte ponovo. + CSRF vrednost nije ispravna. Pokušajte ponovo. + + + This value is not a valid HTML5 color. + Ova vrednost nije ispravna HTML5 boja. + + + Please enter a valid birthdate. + Molim upišite ispravan datum rođenja. + + + The selected choice is invalid. + Odabrani izbor nije ispravan. + + + The collection is invalid. + Ova kolekcija nije ispravna. + + + Please select a valid color. + Molim izaberite ispravnu boju. + + + Please select a valid country. + Molim izaberite ispravnu državu. + + + Please select a valid currency. + Molim izaberite ispravnu valutu. + + + Please choose a valid date interval. + Molim izaberite ispravan datumski interval. + + + Please enter a valid date and time. + Molim upišite ispravan datum i vreme. + + + Please enter a valid date. + Molim upišite ispravan datum. + + + Please select a valid file. + Molim izaberite ispravnu datoteku. + + + The hidden field is invalid. + Skriveno polje nije ispravno. + + + Please enter an integer. + Molim upišite ceo broj (integer). + + + Please select a valid language. + Molim izaberite ispravan jezik. + + + Please select a valid locale. + Molim izaberite ispravnu lokalizaciju. + + + Please enter a valid money amount. + Molim upišite ispravnu količinu novca. + + + Please enter a number. + Molim upišite broj. + + + The password is invalid. + Ova lozinka nije ispravna. + + + Please enter a percentage value. + Molim upišite procentualnu vrednost. + + + The values do not match. + Date vrednosti se ne poklapaju. + + + Please enter a valid time. + Molim upišite ispravno vreme. + + + Please select a valid timezone. + Molim izaberite ispravnu vremensku zonu. + + + Please enter a valid URL. + Molim upišite ispravan URL. + + + Please enter a valid search term. + Molim upišite ispravan termin za pretragu. + + + Please provide a valid phone number. + Molim navedite ispravan broj telefona. diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 29f82ac9b7..a99bfff2e8 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -17,7 +17,6 @@ use Symfony\Component\HttpClient\Chunk\InformationalChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Internal\ClientState; use Symfony\Component\HttpClient\Internal\CurlClientState; -use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -205,14 +204,9 @@ final class CurlResponse implements ResponseInterface return; // Unused pushed response } - $e = null; $this->doDestruct(); - } catch (HttpExceptionInterface $e) { - throw $e; } finally { - if ($e ?? false) { - throw $e; - } + $multi = clone $this->multi; $this->close(); @@ -221,6 +215,8 @@ final class CurlResponse implements ResponseInterface $this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals; $this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = []; } + + $this->multi = $multi; } } @@ -229,7 +225,6 @@ final class CurlResponse implements ResponseInterface */ private function close(): void { - $this->inflate = null; unset($this->multi->openHandles[$this->id], $this->multi->handlesActivity[$this->id]); curl_setopt($this->handle, \CURLOPT_PRIVATE, '_0'); diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index e29005b58f..41eadf1a41 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -16,7 +16,6 @@ use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Internal\ClientState; use Symfony\Component\HttpClient\Internal\NativeClientState; -use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -87,14 +86,9 @@ final class NativeResponse implements ResponseInterface public function __destruct() { try { - $e = null; $this->doDestruct(); - } catch (HttpExceptionInterface $e) { - throw $e; } finally { - if ($e ?? false) { - throw $e; - } + $multi = clone $this->multi; $this->close(); @@ -103,6 +97,8 @@ final class NativeResponse implements ResponseInterface $this->multi->responseCount = 0; $this->multi->dnsCache = []; } + + $this->multi = $multi; } } @@ -197,7 +193,7 @@ final class NativeResponse implements ResponseInterface private function close(): void { unset($this->multi->openHandles[$this->id], $this->multi->handlesActivity[$this->id]); - $this->handle = $this->buffer = $this->inflate = $this->onProgress = null; + $this->handle = $this->buffer = $this->onProgress = null; } /** diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index f8a84ea4bc..bc9c44cbbf 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -12,9 +12,11 @@ namespace Symfony\Component\HttpClient\Tests; use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\Internal\ClientState; use Symfony\Component\HttpClient\Response\StreamWrapper; use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Process; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\Test\HttpClientTestCase as BaseHttpClientTestCase; @@ -246,4 +248,26 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase self::$vulcainStarted = true; } + + public function testHandleIsRemovedOnException() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/304'); + $this->fail(RedirectionExceptionInterface::class.' expected'); + } catch (RedirectionExceptionInterface $e) { + // The response content-type mustn't be json as that calls getContent + // @see src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php:58 + $this->assertStringNotContainsString('json', $e->getResponse()->getHeaders(false)['content-type'][0] ?? ''); + + $r = new \ReflectionProperty($client, 'multi'); + $r->setAccessible(true); + /** @var ClientState $clientState */ + $clientState = $r->getValue($client); + + $this->assertCount(0, $clientState->handlesActivity); + $this->assertCount(0, $clientState->openHandles); + } + } } diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index 4130d70288..73dfb9f074 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -240,6 +240,10 @@ class MockHttpClientTest extends HttpClientTestCase $this->markTestSkipped("MockHttpClient doesn't timeout on destruct"); break; + case 'testHandleIsRemovedOnException': + $this->markTestSkipped("MockHttpClient doesn't cache handles"); + break; + case 'testGetRequest': array_unshift($headers, 'HTTP/1.1 200 OK'); $responses[] = new MockResponse($body, ['response_headers' => $headers]); diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php index 070ef4d775..0ea9aa3b86 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php @@ -30,6 +30,9 @@ class Query extends AbstractQuery /** @var resource[] */ private $results; + /** @var array */ + private $serverctrls = []; + public function __construct(Connection $connection, string $dn, string $query, array $options = []) { parent::__construct($connection, $dn, $query, $options); @@ -97,22 +100,13 @@ class Query extends AbstractQuery $cookie = ''; do { if ($pageControl) { - ldap_control_paged_result($con, $pageSize, true, $cookie); + $this->controlPagedResult($con, $pageSize, $cookie); } $sizeLimit = $itemsLeft; if ($pageSize > 0 && $sizeLimit >= $pageSize) { $sizeLimit = 0; } - $search = @$func( - $con, - $this->dn, - $this->query, - $this->options['filter'], - $this->options['attrsOnly'], - $sizeLimit, - $this->options['timeout'], - $this->options['deref'] - ); + $search = $this->callSearchFunction($con, $func, $sizeLimit); if (false === $search) { $ldapError = ''; @@ -133,7 +127,7 @@ class Query extends AbstractQuery break; } if ($pageControl) { - ldap_control_paged_result_response($con, $search, $cookie); + $cookie = $this->controlPagedResultResponse($con, $search, $cookie); } } while (null !== $cookie && '' !== $cookie); @@ -180,7 +174,8 @@ class Query extends AbstractQuery private function resetPagination() { $con = $this->connection->getResource(); - ldap_control_paged_result($con, 0); + $this->controlPagedResultResponse($con, 0, ''); + $this->serverctrls = []; // This is a workaround for a bit of a bug in the above invocation // of ldap_control_paged_result. Instead of indicating to extldap that @@ -203,4 +198,62 @@ class Query extends AbstractQuery ldap_set_option($con, \LDAP_OPT_SERVER_CONTROLS, $ctl); } } + + /** + * Sets LDAP pagination controls. + * + * @param resource $con + */ + private function controlPagedResult($con, int $pageSize, string $cookie): bool + { + if (\PHP_VERSION_ID < 70300) { + return ldap_control_paged_result($con, $pageSize, true, $cookie); + } + $this->serverctrls = [ + [ + 'oid' => \LDAP_CONTROL_PAGEDRESULTS, + 'isCritical' => true, + 'value' => [ + 'size' => $pageSize, + 'cookie' => $cookie, + ], + ], + ]; + + return true; + } + + /** + * Retrieve LDAP pagination cookie. + * + * @param resource $con + * @param resource $result + */ + private function controlPagedResultResponse($con, $result, string $cookie = ''): string + { + if (\PHP_VERSION_ID < 70300) { + ldap_control_paged_result_response($con, $result, $cookie); + + return $cookie; + } + ldap_parse_result($con, $result, $errcode, $matcheddn, $errmsg, $referrals, $controls); + + return $controls[\LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? ''; + } + + /** + * Calls actual LDAP search function with the prepared options and parameters. + * + * @param resource $con + * + * @return resource + */ + private function callSearchFunction($con, string $func, int $sizeLimit) + { + if (\PHP_VERSION_ID < 70300) { + return @$func($con, $this->dn, $this->query, $this->options['filter'], $this->options['attrsOnly'], $sizeLimit, $this->options['timeout'], $this->options['deref']); + } + + return @$func($con, $this->dn, $this->query, $this->options['filter'], $this->options['attrsOnly'], $sizeLimit, $this->options['timeout'], $this->options['deref'], $this->serverctrls); + } } diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 1d82948e69..7109408121 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -489,7 +489,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) { $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; - if ('null' === $phpTypeOrClass) { + if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass) { continue; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 4e1fae4a35..672f31cb2b 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -240,6 +240,8 @@ class ReflectionExtractorTest extends TestCase ['timeout', [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT)]], ['optional', [new Type(Type::BUILTIN_TYPE_INT, true), new Type(Type::BUILTIN_TYPE_FLOAT, true)]], ['string', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Stringable'), new Type(Type::BUILTIN_TYPE_STRING)]], + ['payload', null], + ['data', null], ]; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php index 484498f4a6..3e1ffba662 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php @@ -23,4 +23,12 @@ class Php80Dummy public function setString(string|\Stringable $string) { } + + public function setPayload(mixed $payload) + { + } + + public function getData(): mixed + { + } } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf index 84c24720da..261b8f34e6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf @@ -290,6 +290,82 @@ The image is square ({{ width }}x{{ height }}px). Square images are not allowed. Pilt on ruudukujuline ({{ width }}x{{ height }}px). Ruudukujulised pildid pole lubatud. + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Pilt on horisontaalselt orienteeritud ({{ width }}x{{ height }}px). Maastikulised pildid pole lubatud. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Pilt on vertikaalselt orienteeritud ({{ width }}x{{ height }}px). Portreepildid pole lubatud. + + + An empty file is not allowed. + Tühi fail pole lubatud. + + + The host could not be resolved. + Peremeest ei õnnestunud lahendada. + + + This value does not match the expected {{ charset }} charset. + See väärtus ei ühti eeldatava tähemärgiga {{ charset }}. + + + This is not a valid Business Identifier Code (BIC). + See ei ole kehtiv ettevõtte identifitseerimiskood (BIC). + + + Error + Viga + + + This is not a valid UUID. + See pole kehtiv UUID. + + + This value should be a multiple of {{ compared_value }}. + See väärtus peaks olema väärtuse {{ compared_value }} kordne. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + See ettevõtte identifitseerimiskood (BIC) ei ole seotud IBAN-iga {{ iban }}. + + + This value should be valid JSON. + See väärtus peaks olema kehtiv JSON. + + + This collection should contain only unique elements. + See kogu peaks sisaldama ainult unikaalseid elemente. + + + This value should be positive. + See väärtus peaks olema positiivne. + + + This value should be either positive or zero. + See väärtus peaks olema kas positiivne või null. + + + This value should be negative. + See väärtus peaks olema negatiivne. + + + This value should be either negative or zero. + See väärtus peaks olema kas negatiivne või null. + + + This value is not a valid timezone. + See väärtus pole kehtiv ajavöönd. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + See parool on lekkinud andmerikkumise korral, seda ei tohi kasutada. Palun kasutage muud parooli. + + + This value should be between {{ min }} and {{ max }}. + See väärtus peaks olema vahemikus {{ min }} kuni {{ max }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index 8616edf4b9..2dbd009ccd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -334,6 +334,58 @@ This value should be valid JSON. Este valor deve ser um JSON válido. + + This collection should contain only unique elements. + Esta coleção deve conter somente elementos únicos. + + + This value should be positive. + Este valor deve ser positivo. + + + This value should be either positive or zero. + Este valor deve ser positivo ou zero. + + + This value should be negative. + Este valor deve ser negativo. + + + This value should be either negative or zero. + Este valor deve ser negativo ou zero. + + + This value is not a valid timezone. + Este valor não representa um fuso horário válido. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Esta senha foi divulgada num vazamento de dados e não deve ser utilizada. Por favor, utilize outra senha. + + + This value should be between {{ min }} and {{ max }}. + Este valor deve estar entre {{ min }} e {{ max }}. + + + This value is not a valid hostname. + Este valor não é um nome de host válido. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + O número de elementos desta coleção deve ser um múltiplo de {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Este valor deve satisfazer pelo menos uma das seguintes restrições: + + + Each element of this collection should satisfy its own set of constraints. + Cada elemento desta coleção deve satisfazer seu próprio grupo de restrições. + + + This value is not a valid International Securities Identification Number (ISIN). + Este valor não é um Número de Identificação de Títulos Internacionais (ISIN) válido. + diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index bdbe3c2c76..08588fc339 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -222,7 +222,7 @@ class VarCloner extends AbstractCloner $stub->position = $len++; } elseif ($pos < $maxItems) { if ($maxItems < $pos += \count($a)) { - $a = \array_slice($a, 0, $maxItems - $pos); + $a = \array_slice($a, 0, $maxItems - $pos, true); if ($stub->cut >= 0) { $stub->cut += $pos - $maxItems; } diff --git a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php index 10bf254176..b472963216 100644 --- a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php @@ -170,7 +170,7 @@ EOTXT; 'Level 3 Item 3', ], [ - 'Level 3 Item 4', + 999 => 'Level 3 Item 4', 'Level 3 Item 5', 'Level 3 Item 6', ], @@ -250,7 +250,7 @@ Symfony\Component\VarDumper\Cloner\Data Object [1] => Array ( [0] => 2 - [2] => 7 + [1] => 7 ) [2] => Array @@ -307,7 +307,7 @@ Symfony\Component\VarDumper\Cloner\Data Object [7] => Array ( - [0] => Level 3 Item 4 + [999] => Level 3 Item 4 ) ) diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index 96486ca316..ed9d4e4045 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -63,6 +63,12 @@ switch ($vars['REQUEST_URI']) { header('Content-Type: application/json', true, 404); break; + case '/404-gzipped': + header('Content-Type: text/plain', true, 404); + ob_start('ob_gzhandler'); + echo 'some text'; + exit; + case '/301': if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) { header('Location: http://127.0.0.1:8057/302', true, 301); @@ -157,7 +163,7 @@ switch ($vars['REQUEST_URI']) { exit; case '/json': - header("Content-Type: application/json"); + header('Content-Type: application/json'); echo json_encode([ 'documents' => [ ['id' => '/json/1'], @@ -170,7 +176,7 @@ switch ($vars['REQUEST_URI']) { case '/json/1': case '/json/2': case '/json/3': - header("Content-Type: application/json"); + header('Content-Type: application/json'); echo json_encode([ 'title' => $vars['REQUEST_URI'], ]); diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 76db9facd7..74997eaafc 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -860,6 +860,18 @@ abstract class HttpClientTestCase extends TestCase } } + public function testGetEncodedContentAfterDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/404-gzipped'); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + $this->assertSame('some text', $e->getResponse()->getContent(false)); + } + } + public function testProxy() { $client = $this->getHttpClient(__FUNCTION__);