diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php index c6667a9fbc..9527fa63ff 100644 --- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php @@ -88,7 +88,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa $item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]]; } $innerItem->set($item["\0*\0value"]); - $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', $item["\0*\0expiry"])) : null); + $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null); }, null, CacheItem::class diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php index e53b407028..4f30fdddd1 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php @@ -24,6 +24,29 @@ class TagAwareAndProxyAdapterIntegrationTest extends TestCase $cache->save($item); $this->assertSame('bar', $cache->getItem('foo')->get()); + + $cache->invalidateTags(['tag2']); + + $this->assertFalse($cache->getItem('foo')->isHit()); + } + + public function testIntegrationUsingProxiedAdapterForTagsPool() + { + $arrayAdapter = new ArrayAdapter(); + $cache = new TagAwareAdapter($arrayAdapter, new ProxyAdapter($arrayAdapter)); + + $item = $cache->getItem('foo'); + $item->expiresAfter(600); + $item->tag(['baz']); + $item->set('bar'); + $cache->save($item); + + $this->assertSame('bar', $cache->getItem('foo')->get()); + $this->assertTrue($cache->getItem('foo')->isHit()); + + $cache->invalidateTags(['baz']); + + $this->assertFalse($cache->getItem('foo')->isHit()); } public function dataProvider(): array diff --git a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php index 5e102bf318..de3dbfc7a8 100644 --- a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php +++ b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php @@ -128,7 +128,7 @@ trait AbstractAdapterTrait } } $namespaceToClear = $this->namespace.$namespaceVersionToClear; - $namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5); + $namespaceVersion = strtr(substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5), '/', '_'); try { $cleared = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0); } catch (\Exception $e) { @@ -340,7 +340,7 @@ trait AbstractAdapterTrait try { foreach ($items as $id => $value) { if (!isset($keys[$id])) { - $id = key($keys); + throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys))); } $key = $keys[$id]; unset($keys[$id]); @@ -365,7 +365,7 @@ trait AbstractAdapterTrait $this->namespaceVersion = $v; } if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) { - $this->namespaceVersion = substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5); + $this->namespaceVersion = strtr(substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5), '/', '_'); $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0); } } catch (\Exception $e) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 58da243d9c..fd25b64f7a 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -2056,7 +2056,15 @@ EOF; $suffix = $matches[0][1] + \strlen($matches[0][0]); $matches[0][1] += \strlen($matches[1][0]); $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; - $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; + + if ('\\' === \DIRECTORY_SEPARATOR && isset($value[$suffix])) { + $cookie = '\\'.random_int(100000, \PHP_INT_MAX); + $suffix = '.'.$this->doExport(str_replace('\\', $cookie, substr($value, $suffix)), true); + $suffix = str_replace('\\'.$cookie, "'.\\DIRECTORY_SEPARATOR.'", $suffix); + } else { + $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; + } + $dirname = $this->asFiles ? '$this->containerDir' : '__DIR__'; $offset = 2 + $this->targetDirMaxMatches - \count($matches); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index e02de5e2fc..f66959d0eb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -239,7 +239,7 @@ class PhpDumperTest extends TestCase $dumper = new PhpDumper($container); $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true); if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace('\\\\Fixtures\\\\includes\\\\foo.php', '/Fixtures/includes/foo.php', $dump); + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); } $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_as_files.txt', $dump); } @@ -266,7 +266,7 @@ class PhpDumperTest extends TestCase $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'build_time' => 1563381341]), true); if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace('\\\\Fixtures\\\\includes\\\\', '/Fixtures/includes/', $dump); + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); } $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_inlined_factories.txt', $dump); } @@ -292,7 +292,7 @@ class PhpDumperTest extends TestCase $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'build_time' => 1563381341]), true); if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace('\\\\Fixtures\\\\includes\\\\', '/Fixtures/includes/', $dump); + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); } $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_lazy_inlined_factories.txt', $dump); } @@ -310,7 +310,7 @@ class PhpDumperTest extends TestCase $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true); if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace('\\\\Fixtures\\\\includes\\\\foo_lazy.php', '/Fixtures/includes/foo_lazy.php', $dump); + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); } $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services_non_shared_lazy_as_files.txt', $dump); } @@ -986,7 +986,7 @@ class PhpDumperTest extends TestCase $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_array_params.php', str_replace('\\\\Dumper', '/Dumper', $dumper->dump(['file' => self::$fixturesPath.'/php/services_array_params.php', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]))); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_array_params.php', str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dumper->dump(['file' => self::$fixturesPath.'/php/services_array_params.php', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]))); } public function testExpressionReferencingPrivateService() @@ -1149,7 +1149,7 @@ class PhpDumperTest extends TestCase $dump = $dumper->dump(['hot_path_tag' => 'container.hot_path', 'inline_class_loader_parameter' => 'inline_requires', 'file' => self::$fixturesPath.'/php/services_inline_requires.php']); if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace("'\\\\includes\\\\HotPath\\\\", "'/includes/HotPath/", $dump); + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); } $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_requires.php', $dump); diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 060c2d3ec2..6ed37e71a3 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -237,7 +237,7 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface { if (null !== $this->scale && null !== $this->roundingMode) { // shift number to maintain the correct scale during rounding - $roundingCoef = pow(10, $this->scale); + $roundingCoef = 10 ** $this->scale; // string representation to avoid rounding errors, similar to bcmul() $number = (string) ($number * $roundingCoef); diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php index b7e6eef38b..5e8facd4cf 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php @@ -338,10 +338,10 @@ abstract class AbstractRequestHandlerTest extends TestCase public function getPostMaxSizeFixtures() { return [ - [pow(1024, 3) + 1, '1G', true, ['{{ max }}' => '1G']], - [pow(1024, 3), '1G', false], - [pow(1024, 2) + 1, '1M', true, ['{{ max }}' => '1M']], - [pow(1024, 2), '1M', false], + [1024 ** 3 + 1, '1G', true, ['{{ max }}' => '1G']], + [1024 ** 3, '1G', false], + [1024 ** 2 + 1, '1M', true, ['{{ max }}' => '1M']], + [1024 ** 2, '1M', false], [1024 + 1, '1K', true, ['{{ max }}' => '1K']], [1024, '1K', false], [null, '1K', false], diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index a65004675d..29f82ac9b7 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -123,6 +123,19 @@ final class CurlResponse implements ResponseInterface } curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { + if ('H' === (curl_getinfo($ch, \CURLINFO_PRIVATE)[0] ?? null)) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = new TransportException(sprintf('Unsupported protocol for "%s"', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); + + return 0; + } + + curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { + $multi->handlesActivity[$id][] = $data; + + return \strlen($data); + }); + $multi->handlesActivity[$id][] = $data; return \strlen($data); diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 65eb6e468e..76af2dfa7e 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -270,7 +270,7 @@ trait ResponseTrait $debug .= "< \r\n"; if (!$info['http_code']) { - throw new TransportException('Invalid or missing HTTP status line.'); + throw new TransportException(sprintf('Invalid or missing HTTP status line for "%s".', implode('', $info['url']))); } } @@ -350,7 +350,7 @@ trait ResponseTrait if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) { if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) { - $multi->handlesActivity[$j] = [null, new TransportException('Error while processing content unencoding.')]; + $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Error while processing content unencoding for "%s".', $response->getInfo('url')))]; continue; } diff --git a/src/Symfony/Component/HttpClient/Tests/CachingHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CachingHttpClientTest.php index 0525feed6c..ad07f86451 100644 --- a/src/Symfony/Component/HttpClient/Tests/CachingHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/CachingHttpClientTest.php @@ -89,7 +89,7 @@ class CachingHttpClientTest extends TestCase 'test', [ 'response_headers' => [ 'X-Content-Digest' => 'some-hash', - ] + ], ])); $headers = $response->getHeaders(); @@ -100,7 +100,7 @@ class CachingHttpClientTest extends TestCase { $mockClient = new MockHttpClient($mockResponse); - $store = new Store(sys_get_temp_dir() . '/sf_http_cache'); + $store = new Store(sys_get_temp_dir().'/sf_http_cache'); $client = new CachingHttpClient($mockClient, $store); $response = $client->request('GET', 'http://test'); diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index 05299679da..40223dc86d 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -691,7 +691,7 @@ abstract class NumberFormatter // Swiss rounding if (0 < $roundingIncrement && 0 < $fractionDigits) { - $roundingFactor = $roundingIncrement / pow(10, $fractionDigits); + $roundingFactor = $roundingIncrement / 10 ** $fractionDigits; $value = round($value / $roundingFactor) * $roundingFactor; } @@ -713,7 +713,7 @@ abstract class NumberFormatter if (isset(self::$phpRoundingMap[$roundingModeAttribute])) { $value = round($value, $precision, self::$phpRoundingMap[$roundingModeAttribute]); } elseif (isset(self::$customRoundingList[$roundingModeAttribute])) { - $roundingCoef = pow(10, $precision); + $roundingCoef = 10 ** $precision; $value *= $roundingCoef; $value = (float) (string) $value; diff --git a/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php b/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php index cf72f8614f..8f5c1cdc3f 100644 --- a/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php +++ b/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php @@ -80,7 +80,7 @@ class MultiplierRetryStrategy implements RetryStrategyInterface { $retries = RedeliveryStamp::getRetryCountFromEnvelope($message); - $delay = $this->delayMilliseconds * pow($this->multiplier, $retries); + $delay = $this->delayMilliseconds * $this->multiplier ** $retries; if ($delay > $this->maxDelayMilliseconds && 0 !== $this->maxDelayMilliseconds) { return $this->maxDelayMilliseconds; diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf index 3f2b9eaba8..fce95a0769 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf @@ -366,6 +366,26 @@ This value should be between {{ min }} and {{ max }}. Ова вредност треба да буде између {{ min }} и {{ max }}. + + This value is not a valid hostname. + Ова вредност није исправно име послужитеља (hostname). + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Број елемената у овој колекцији би требало да буде дељив са {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Ова вредност би требало да задовољава најмање једно од наредних ограничења: + + + Each element of this collection should satisfy its own set of constraints. + Сваки елемент ове колекције би требало да задовољи сопствени скуп ограничења. + + + This value is not a valid International Securities Identification Number (ISIN). + Ова вредност није исправна међународна идентификациона ознака хартија од вредности (ISIN). + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 43d2070ab7..06b164be8a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -366,6 +366,26 @@ This value should be between {{ min }} and {{ max }}. Ova vrednost treba da bude između {{ min }} i {{ max }}. + + This value is not a valid hostname. + Ova vrednost nije ispravno ime poslužitelja (hostname). + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Broj elemenata u ovoj kolekciji bi trebalo da bude deljiv sa {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Ova vrednost bi trebalo da zadovoljava namjanje jedno od narednih ograničenja: + + + Each element of this collection should satisfy its own set of constraints. + Svaki element ove kolekcije bi trebalo da zadovolji sopstveni skup ograničenja. + + + This value is not a valid International Securities Identification Number (ISIN). + Ova vrednost nije ispravna međunarodna identifikaciona oznaka hartija od vrednosti (ISIN). + diff --git a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php index 6ac799c7a8..e823c886bd 100644 --- a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php @@ -113,10 +113,45 @@ abstract class ConstraintValidatorTestCase extends TestCase $context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); $context->setConstraint($this->constraint); + $contextualValidator = $this->getMockBuilder(AssertingContextualValidator::class) + ->setConstructorArgs([$context]) + ->setMethods([ + 'atPath', + 'validate', + 'validateProperty', + 'validatePropertyValue', + 'getViolations', + ]) + ->getMock(); + $contextualValidator->expects($this->any()) + ->method('atPath') + ->willReturnCallback(function ($path) use ($contextualValidator) { + return $contextualValidator->doAtPath($path); + }); + $contextualValidator->expects($this->any()) + ->method('validate') + ->willReturnCallback(function ($value, $constraints = null, $groups = null) use ($contextualValidator) { + return $contextualValidator->doValidate($value, $constraints, $groups); + }); + $contextualValidator->expects($this->any()) + ->method('validateProperty') + ->willReturnCallback(function ($object, $propertyName, $groups = null) use ($contextualValidator) { + return $contextualValidator->validateProperty($object, $propertyName, $groups); + }); + $contextualValidator->expects($this->any()) + ->method('validatePropertyValue') + ->willReturnCallback(function ($objectOrClass, $propertyName, $value, $groups = null) use ($contextualValidator) { + return $contextualValidator->doValidatePropertyValue($objectOrClass, $propertyName, $value, $groups); + }); + $contextualValidator->expects($this->any()) + ->method('getViolations') + ->willReturnCallback(function () use ($contextualValidator) { + return $contextualValidator->doGetViolations(); + }); $validator->expects($this->any()) ->method('inContext') ->with($context) - ->willReturn($this->getMockBuilder(AssertingContextualValidator::class)->setConstructorArgs([$context])->setMethods(null)->getMock()); + ->willReturn($contextualValidator); return $context; } @@ -403,6 +438,10 @@ class AssertingContextualValidator implements ContextualValidatorInterface } public function atPath($path) + { + } + + public function doAtPath($path) { Assert::assertFalse($this->expectNoValidate, 'No validation calls have been expected.'); @@ -416,6 +455,10 @@ class AssertingContextualValidator implements ContextualValidatorInterface } public function validate($value, $constraints = null, $groups = null) + { + } + + public function doValidate($value, $constraints = null, $groups = null) { Assert::assertFalse($this->expectNoValidate, 'No validation calls have been expected.'); @@ -437,11 +480,19 @@ class AssertingContextualValidator implements ContextualValidatorInterface } public function validateProperty($object, $propertyName, $groups = null) + { + } + + public function doValidateProperty($object, $propertyName, $groups = null) { return $this; } public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null) + { + } + + public function doValidatePropertyValue($objectOrClass, $propertyName, $value, $groups = null) { return $this; } @@ -451,6 +502,10 @@ class AssertingContextualValidator implements ContextualValidatorInterface return $this->context->getViolations(); } + public function doGetViolations() + { + } + public function expectNoValidate() { $this->expectNoValidate = true;