+ {% endif %}
{% for attachment in message.attachments %}
Attachment #{{ loop.index }}
diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php
index 758fc14ee1de7..d4be13197543d 100644
--- a/src/Symfony/Component/BrowserKit/Cookie.php
+++ b/src/Symfony/Component/BrowserKit/Cookie.php
@@ -311,8 +311,6 @@ public function isExpired()
/**
* Gets the samesite attribute of the cookie.
- *
- * @return string|null
*/
public function getSameSite(): ?string
{
diff --git a/src/Symfony/Component/BrowserKit/Response.php b/src/Symfony/Component/BrowserKit/Response.php
index 65e7fd29a0d72..f38ca4f879d0f 100644
--- a/src/Symfony/Component/BrowserKit/Response.php
+++ b/src/Symfony/Component/BrowserKit/Response.php
@@ -37,8 +37,6 @@ public function __construct(string $content = '', int $status = 200, array $head
/**
* Converts the response object to string containing all headers and the response content.
- *
- * @return string
*/
public function __toString(): string
{
@@ -58,8 +56,6 @@ public function __toString(): string
/**
* Gets the response content.
- *
- * @return string
*/
public function getContent(): string
{
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
index b2dec6152b945..3209f5c203164 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
@@ -74,7 +74,7 @@ static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime)
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
- } elseif (0 === $item->expiry) {
+ } elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
index d062a94468e26..4f69c2a400181 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
@@ -79,7 +79,7 @@ static function ($deferred, &$expiredIds, $getId, $tagPrefix, $defaultLifetime)
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
- } elseif (0 === $item->expiry) {
+ } elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
@@ -151,8 +151,6 @@ abstract protected function doDeleteTagRelations(array $tagData): bool;
* Invalidates cached items using tags.
*
* @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id
- *
- * @return bool
*/
abstract protected function doInvalidate(array $tagIds): bool;
diff --git a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
index 6fda0ef37f262..5fc8f6295b30c 100644
--- a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
@@ -60,7 +60,14 @@ protected function doFetch(array $ids)
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
$values = [];
- foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) {
+ $ids = array_flip($ids);
+ foreach (apcu_fetch(array_keys($ids), $ok) ?: [] as $k => $v) {
+ if (!isset($ids[$k])) {
+ // work around https://github.com/krakjoe/apcu/issues/247
+ $k = key($ids);
+ }
+ unset($ids[$k]);
+
if (null !== $v || $ok) {
$values[$k] = null !== $this->marshaller ? $this->marshaller->unmarshall($v) : $v;
}
diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
index 0fa78d07c14a9..bd5ec9ec9884b 100644
--- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
@@ -190,14 +190,14 @@ public function save(CacheItemInterface $item)
$now = microtime(true);
- if (0 === $expiry) {
- $expiry = \PHP_INT_MAX;
- }
-
- if (null !== $expiry && $expiry <= $now) {
- $this->deleteItem($key);
+ if (null !== $expiry) {
+ if (!$expiry) {
+ $expiry = \PHP_INT_MAX;
+ } elseif ($expiry <= $now) {
+ $this->deleteItem($key);
- return true;
+ return true;
+ }
}
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
index 7291a7e48f6e0..c715cade5c1f0 100644
--- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
@@ -92,7 +92,7 @@ static function (CacheItemInterface $innerItem, array $item) {
$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', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null);
+ $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
},
null,
CacheItem::class
diff --git a/src/Symfony/Component/Cache/CHANGELOG.md b/src/Symfony/Component/Cache/CHANGELOG.md
index 0654b0389ad6a..60a862740d1e7 100644
--- a/src/Symfony/Component/Cache/CHANGELOG.md
+++ b/src/Symfony/Component/Cache/CHANGELOG.md
@@ -4,7 +4,6 @@ CHANGELOG
5.4
---
- * Make `LockRegistry` use semaphores when possible
* Deprecate `DoctrineProvider` and `DoctrineAdapter` because these classes have been added to the `doctrine/cache` package
* Add `DoctrineDbalAdapter` identical to `PdoAdapter` for `Doctrine\DBAL\Connection` or DBAL URL
* Deprecate usage of `PdoAdapter` with `Doctrine\DBAL\Connection` or DBAL URL
diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php
index 910c11fae29c4..23e5b4eb294d7 100644
--- a/src/Symfony/Component/Cache/LockRegistry.php
+++ b/src/Symfony/Component/Cache/LockRegistry.php
@@ -27,7 +27,7 @@
final class LockRegistry
{
private static $openedFiles = [];
- private static $lockedKeys;
+ private static $lockedFiles;
/**
* The number of items in this list controls the max number of concurrent processes.
@@ -77,25 +77,21 @@ public static function setFiles(array $files): array
fclose($file);
}
}
- self::$openedFiles = self::$lockedKeys = [];
+ self::$openedFiles = self::$lockedFiles = [];
return $previousFiles;
}
public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null)
{
- if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedKeys) {
+ if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
// disable locking on Windows by default
- self::$files = self::$lockedKeys = [];
+ self::$files = self::$lockedFiles = [];
}
- $key = unpack('i', md5($item->getKey(), true))[1];
+ $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1;
- if (!\function_exists('sem_get')) {
- $key = self::$files ? abs($key) % \count(self::$files) : null;
- }
-
- if (null === $key || (self::$lockedKeys[$key] ?? false) || !$lock = self::open($key)) {
+ if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) {
return $callback($item, $save);
}
@@ -103,15 +99,11 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
try {
$locked = false;
// race to get the lock in non-blocking mode
- if ($wouldBlock = \function_exists('sem_get')) {
- $locked = @sem_acquire($lock, true);
- } else {
- $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
- }
+ $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
if ($locked || !$wouldBlock) {
$logger && $logger->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]);
- self::$lockedKeys[$key] = true;
+ self::$lockedFiles[$key] = true;
$value = $callback($item, $save);
@@ -126,25 +118,12 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
return $value;
}
-
// if we failed the race, retry locking in blocking mode to wait for the winner
$logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
-
- if (\function_exists('sem_get')) {
- $lock = sem_get($key);
- @sem_acquire($lock);
- } else {
- flock($lock, \LOCK_SH);
- }
+ flock($lock, \LOCK_SH);
} finally {
- if ($locked) {
- if (\function_exists('sem_get')) {
- sem_remove($lock);
- } else {
- flock($lock, \LOCK_UN);
- }
- }
- unset(self::$lockedKeys[$key]);
+ flock($lock, \LOCK_UN);
+ unset(self::$lockedFiles[$key]);
}
static $signalingException, $signalingCallback;
$signalingException = $signalingException ?? unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}");
@@ -169,10 +148,6 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
private static function open(int $key)
{
- if (\function_exists('sem_get')) {
- return sem_get($key);
- }
-
if (null !== $h = self::$openedFiles[$key] ?? null) {
return $h;
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
index b67fb5cd0cc79..36d487fe14105 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
@@ -128,7 +128,7 @@ public function testGetMetadata()
$metadata = $item->getMetadata();
$this->assertArrayHasKey(CacheItem::METADATA_CTIME, $metadata);
- $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 10);
+ $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 150);
$this->assertArrayHasKey(CacheItem::METADATA_EXPIRY, $metadata);
$this->assertEqualsWithDelta(9 + time(), $metadata[CacheItem::METADATA_EXPIRY], 1);
}
@@ -306,6 +306,15 @@ public function testWeirdDataMatchingMetadataWrappedValues()
$this->assertTrue($cache->hasItem('foobar'));
}
+
+ public function testNullByteInKey()
+ {
+ $cache = $this->createCachePool(0, __FUNCTION__);
+
+ $cache->save($cache->getItem("a\0b")->set(123));
+
+ $this->assertSame(123, $cache->getItem("a\0b")->get());
+ }
}
class NotUnserializable
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
new file mode 100644
index 0000000000000..46516e0095e6e
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Adapter;
+
+use Psr\Cache\CacheItemPoolInterface;
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
+use Symfony\Component\Cache\Adapter\ProxyAdapter;
+use Symfony\Component\Cache\Adapter\RedisAdapter;
+use Symfony\Component\Cache\CacheItem;
+
+/**
+ * @group integration
+ */
+class ProxyAdapterAndRedisAdapterTest extends AbstractRedisAdapterTest
+{
+ protected $skippedTests = [
+ 'testPrune' => 'RedisAdapter does not implement PruneableInterface.',
+ ];
+
+ public static function setUpBeforeClass(): void
+ {
+ parent::setUpBeforeClass();
+ self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
+ }
+
+ public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ {
+ return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime);
+ }
+
+ public function testSaveItemPermanently()
+ {
+ $setCacheItemExpiry = \Closure::bind(
+ static function (CacheItem $item, $expiry) {
+ $item->expiry = $expiry;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+
+ $cache = $this->createCachePool(1);
+ $value = rand();
+ $item = $cache->getItem('foo');
+ $setCacheItemExpiry($item, 0);
+ $cache->save($item->set($value));
+ $item = $cache->getItem('bar');
+ $setCacheItemExpiry($item, 0.0);
+ $cache->save($item->set($value));
+ $item = $cache->getItem('baz');
+ $cache->save($item->set($value));
+
+ $this->assertSame($value, $this->cache->getItem('foo')->get());
+ $this->assertSame($value, $this->cache->getItem('bar')->get());
+ $this->assertSame($value, $this->cache->getItem('baz')->get());
+
+ sleep(1);
+ $this->assertSame($value, $this->cache->getItem('foo')->get());
+ $this->assertSame($value, $this->cache->getItem('bar')->get());
+ $this->assertFalse($this->cache->getItem('baz')->isHit());
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
index b688ad46ed440..355368f465777 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
@@ -14,12 +14,10 @@
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
-use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
-use Symfony\Component\Cache\LockRegistry;
use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter;
use Symfony\Component\Filesystem\Filesystem;
@@ -181,24 +179,6 @@ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags
$this->assertFalse($item->isHit());
}
- public function testLog()
- {
- $lockFiles = LockRegistry::setFiles([__FILE__]);
-
- $logger = $this->createMock(LoggerInterface::class);
- $logger
- ->expects($this->atLeastOnce())
- ->method($this->anything());
-
- $cache = new TagAwareAdapter(new ArrayAdapter());
- $cache->setLogger($logger);
-
- // Computing will produce at least one log
- $cache->get('foo', static function (): string { return 'ccc'; });
-
- LockRegistry::setFiles($lockFiles);
- }
-
/**
* @return MockObject&PruneableCacheInterface
*/
diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
index 2f5af04b075cc..9a491adb5acb8 100644
--- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php
+++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
@@ -31,7 +31,7 @@ trait ContractsTrait
doGet as private contractsGet;
}
- private $callbackWrapper = [LockRegistry::class, 'compute'];
+ private $callbackWrapper;
private $computing = [];
/**
@@ -41,8 +41,16 @@ trait ContractsTrait
*/
public function setCallbackWrapper(?callable $callbackWrapper): callable
{
+ if (!isset($this->callbackWrapper)) {
+ $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']);
+
+ if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
+ $this->setCallbackWrapper(null);
+ }
+ }
+
$previousWrapper = $this->callbackWrapper;
- $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
+ $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
return $callback($item, $save);
};
@@ -82,6 +90,10 @@ static function (CacheItem $item, float $startTime, ?array &$metadata) {
$this->computing[$key] = $key;
$startTime = microtime(true);
+ if (!isset($this->callbackWrapper)) {
+ $this->setCallbackWrapper($this->setCallbackWrapper(null));
+ }
+
try {
$value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$setMetadata($item, $startTime, $metadata);
diff --git a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
index c845c76ed3ced..c622d606bc303 100644
--- a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
+++ b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
@@ -169,6 +169,8 @@ public function getDataForPhpize(): array
[1, '1'],
[-1, '-1'],
[0777, '0777'],
+ [-511, '-0777'],
+ ['0877', '0877'],
[255, '0xFF'],
[100.0, '1e2'],
[-120.0, '-1.2E2'],
diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php
index 9f32b5a62a33f..8258a0627a571 100644
--- a/src/Symfony/Component/Config/Util/XmlUtils.php
+++ b/src/Symfony/Component/Config/Util/XmlUtils.php
@@ -236,15 +236,11 @@ public static function phpize($value)
case 'null' === $lowercaseValue:
return null;
case ctype_digit($value):
- $raw = $value;
- $cast = (int) $value;
-
- return '0' == $value[0] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw);
case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)):
$raw = $value;
$cast = (int) $value;
- return '0' == $value[1] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw);
+ return self::isOctal($value) ? \intval($value, 8) : (($raw === (string) $cast) ? $cast : $raw);
case 'true' === $lowercaseValue:
return true;
case 'false' === $lowercaseValue:
@@ -281,4 +277,13 @@ protected static function getXmlErrors(bool $internalErrors)
return $errors;
}
+
+ private static function isOctal(string $str): bool
+ {
+ if ('-' === $str[0]) {
+ $str = substr($str, 1);
+ }
+
+ return $str === '0'.decoct(\intval($str, 8));
+ }
}
diff --git a/src/Symfony/Component/Console/Completion/CompletionInput.php b/src/Symfony/Component/Console/Completion/CompletionInput.php
index eda95bef55468..368b945079484 100644
--- a/src/Symfony/Component/Console/Completion/CompletionInput.php
+++ b/src/Symfony/Component/Console/Completion/CompletionInput.php
@@ -109,12 +109,12 @@ public function bind(InputDefinition $definition): void
// complete argument value
$this->completionType = self::TYPE_ARGUMENT_VALUE;
- $arguments = $this->getArguments();
- foreach ($arguments as $argumentName => $argumentValue) {
- if (null === $argumentValue) {
+ foreach ($this->definition->getArguments() as $argumentName => $argument) {
+ if (!isset($this->arguments[$argumentName])) {
break;
}
+ $argumentValue = $this->arguments[$argumentName];
$this->completionName = $argumentName;
if (\is_array($argumentValue)) {
$this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null;
@@ -124,7 +124,7 @@ public function bind(InputDefinition $definition): void
}
if ($this->currentIndex >= \count($this->tokens)) {
- if (null === $arguments[$argumentName] || $this->definition->getArgument($argumentName)->isArray()) {
+ if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) {
$this->completionName = $argumentName;
$this->completionValue = '';
} else {
diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php
index 87d3e65394edd..4ea3d724d88dc 100644
--- a/src/Symfony/Component/Console/Helper/ProcessHelper.php
+++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php
@@ -31,8 +31,6 @@ class ProcessHelper extends Helper
* @param array|Process $cmd An instance of Process or an array of the command and arguments
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
- *
- * @return Process
*/
public function run(OutputInterface $output, $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
{
@@ -96,8 +94,6 @@ public function run(OutputInterface $output, $cmd, string $error = null, callabl
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*
- * @return Process
- *
* @throws ProcessFailedException
*
* @see run()
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index 9f9620739a8ee..fe1f27fcc83d5 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -883,6 +883,9 @@ public function testRenderExceptionLineBreaks()
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks');
}
+ /**
+ * @group transient-on-windows
+ */
public function testRenderAnonymousException()
{
$application = new Application();
@@ -906,6 +909,9 @@ public function testRenderAnonymousException()
$this->assertStringContainsString('Dummy type "class@anonymous" is invalid.', $tester->getDisplay(true));
}
+ /**
+ * @group transient-on-windows
+ */
public function testRenderExceptionStackTraceContainsRootException()
{
$application = new Application();
diff --git a/src/Symfony/Component/Console/Tests/Command/HelpCommandTest.php b/src/Symfony/Component/Console/Tests/Command/HelpCommandTest.php
index bf0ab972061bc..0e8a7f4f7fd1a 100644
--- a/src/Symfony/Component/Console/Tests/Command/HelpCommandTest.php
+++ b/src/Symfony/Component/Console/Tests/Command/HelpCommandTest.php
@@ -92,7 +92,7 @@ public function provideCompletionSuggestions()
yield 'nothing' => [
[''],
- [],
+ ['completion', 'help', 'list', 'foo:bar'],
];
yield 'command_name' => [
diff --git a/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php b/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
index f83a0f89893aa..ee370076c17ac 100644
--- a/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
+++ b/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
@@ -97,6 +97,20 @@ public function provideBindWithLastArrayArgumentData()
yield [CompletionInput::fromTokens(['bin/console', 'symfony', 'sen'], 2), 'sen'];
}
+ public function testBindArgumentWithDefault()
+ {
+ $definition = new InputDefinition([
+ new InputArgument('arg-with-default', InputArgument::OPTIONAL, '', 'default'),
+ ]);
+
+ $input = CompletionInput::fromTokens(['bin/console'], 1);
+ $input->bind($definition);
+
+ $this->assertEquals(CompletionInput::TYPE_ARGUMENT_VALUE, $input->getCompletionType(), 'Unexpected type');
+ $this->assertEquals('arg-with-default', $input->getCompletionName(), 'Unexpected name');
+ $this->assertEquals('', $input->getCompletionValue(), 'Unexpected value');
+ }
+
/**
* @dataProvider provideFromStringData
*/
diff --git a/src/Symfony/Component/CssSelector/Parser/TokenStream.php b/src/Symfony/Component/CssSelector/Parser/TokenStream.php
index 70d109f03a57b..2085f2dd76f2b 100644
--- a/src/Symfony/Component/CssSelector/Parser/TokenStream.php
+++ b/src/Symfony/Component/CssSelector/Parser/TokenStream.php
@@ -120,8 +120,6 @@ public function getUsed(): array
/**
* Returns next identifier token.
*
- * @return string
- *
* @throws SyntaxErrorException If next token is not an identifier
*/
public function getNextIdentifier(): string
@@ -138,8 +136,6 @@ public function getNextIdentifier(): string
/**
* Returns next identifier or null if star delimiter token is found.
*
- * @return string|null
- *
* @throws SyntaxErrorException If next token is not an identifier or a star delimiter
*/
public function getNextIdentifierOrStar(): ?string
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
index 01c82a8746cf5..362c5f5718298 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
+use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\LogicException;
@@ -128,25 +129,35 @@ protected function getConstructor(Definition $definition, bool $required)
if ($factory) {
[$class, $method] = $factory;
+
+ if ('__construct' === $method) {
+ throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
+ }
+
if ($class instanceof Reference) {
- $class = $this->container->findDefinition((string) $class)->getClass();
+ $factoryDefinition = $this->container->findDefinition((string) $class);
+ while ((null === $class = $factoryDefinition->getClass()) && $factoryDefinition instanceof ChildDefinition) {
+ $factoryDefinition = $this->container->findDefinition($factoryDefinition->getParent());
+ }
} elseif ($class instanceof Definition) {
$class = $class->getClass();
} elseif (null === $class) {
$class = $definition->getClass();
}
- if ('__construct' === $method) {
- throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
- }
-
return $this->getReflectionMethod(new Definition($class), $method);
}
- $class = $definition->getClass();
+ while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) {
+ $definition = $this->container->findDefinition($definition->getParent());
+ }
try {
if (!$r = $this->container->getReflectionClass($class)) {
+ if (null === $class) {
+ throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId));
+ }
+
throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
}
} catch (\ReflectionException $e) {
@@ -174,7 +185,11 @@ protected function getReflectionMethod(Definition $definition, string $method)
return $this->getConstructor($definition, true);
}
- if (!$class = $definition->getClass()) {
+ while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) {
+ $definition = $this->container->findDefinition($definition->getParent());
+ }
+
+ if (null === $class) {
throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId));
}
@@ -183,6 +198,10 @@ protected function getReflectionMethod(Definition $definition, string $method)
}
if (!$r->hasMethod($method)) {
+ if ($r->hasMethod('__call') && ($r = $r->getMethod('__call')) && $r->isPublic()) {
+ return new \ReflectionMethod(static function (...$arguments) {}, '__invoke');
+ }
+
throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
index d6db29235ef0c..c71ea503bfc0b 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
@@ -134,6 +134,11 @@ protected function processValue($value, bool $isRoot = false)
continue;
}
+ if (is_subclass_of($m[1], \UnitEnum::class)) {
+ $bindingNames[substr($key, \strlen($m[0]))] = $binding;
+ continue;
+ }
+
if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) {
throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, get_debug_type($bindingValue)));
}
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
index 6dfc1669fa837..4f7b16d5f1035 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
@@ -143,7 +143,7 @@ private function addService(Definition $definition, ?string $id, \DOMElement $pa
$tag->appendChild($this->document->createTextNode($name));
}
foreach ($attributes as $key => $value) {
- $tag->setAttribute($key, $value);
+ $tag->setAttribute($key, $value ?? '');
}
$service->appendChild($tag);
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
index b1e9038ae1e18..3815b28f00fba 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
@@ -137,7 +137,7 @@ private function executeCallback(callable $callback, ContainerConfigurator $cont
default:
try {
$configBuilder = $this->configBuilder($type);
- } catch (InvalidArgumentException | \LogicException $e) {
+ } catch (InvalidArgumentException|\LogicException $e) {
throw new \InvalidArgumentException(sprintf('Could not resolve argument "%s" for "%s".', $type.' $'.$parameter->getName(), $path), 0, $e);
}
$configBuilders[] = $configBuilder;
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php
new file mode 100644
index 0000000000000..aecdc9a5a2169
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php
@@ -0,0 +1,127 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Tests\Compiler;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\ChildDefinition;
+use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy;
+
+class AbstractRecursivePassTest extends TestCase
+{
+ public function testGetConstructorResolvesFactoryChildDefinitionsClass()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('factory_dummy_class', FactoryDummy::class);
+ $container
+ ->register('parent', '%factory_dummy_class%')
+ ->setAbstract(true);
+ $container->setDefinition('child', new ChildDefinition('parent'));
+ $container
+ ->register('foo', \stdClass::class)
+ ->setFactory([new Reference('child'), 'createFactory']);
+
+ $pass = new class() extends AbstractRecursivePass {
+ public $actual;
+
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->actual = $this->getConstructor($value, true);
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ };
+ $pass->process($container);
+
+ $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual);
+ $this->assertSame(FactoryDummy::class, $pass->actual->class);
+ }
+
+ public function testGetConstructorResolvesChildDefinitionsClass()
+ {
+ $container = new ContainerBuilder();
+ $container
+ ->register('parent', Bar::class)
+ ->setAbstract(true);
+ $container->setDefinition('foo', new ChildDefinition('parent'));
+
+ $pass = new class() extends AbstractRecursivePass {
+ public $actual;
+
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->actual = $this->getConstructor($value, true);
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ };
+ $pass->process($container);
+
+ $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual);
+ $this->assertSame(Bar::class, $pass->actual->class);
+ }
+
+ public function testGetReflectionMethodResolvesChildDefinitionsClass()
+ {
+ $container = new ContainerBuilder();
+ $container
+ ->register('parent', Bar::class)
+ ->setAbstract(true);
+ $container->setDefinition('foo', new ChildDefinition('parent'));
+
+ $pass = new class() extends AbstractRecursivePass {
+ public $actual;
+
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->actual = $this->getReflectionMethod($value, 'create');
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ };
+ $pass->process($container);
+
+ $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual);
+ $this->assertSame(Bar::class, $pass->actual->class);
+ }
+
+ public function testGetConstructorDefinitionNoClass()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Invalid service "foo": the class is not set.');
+
+ $container = new ContainerBuilder();
+ $container->register('foo');
+
+ (new class() extends AbstractRecursivePass {
+ protected function processValue($value, $isRoot = false)
+ {
+ if ($value instanceof Definition && 'foo' === $this->currentId) {
+ $this->getConstructor($value, true);
+ }
+
+ return parent::processValue($value, $isRoot);
+ }
+ })->process($container);
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
index 8c15ebfa10487..38538f27b0f9f 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
@@ -985,4 +985,22 @@ public function testIntersectionTypeFailsWithReference()
(new CheckTypeDeclarationsPass(true))->process($container);
}
+
+ public function testCallableClass()
+ {
+ $container = new ContainerBuilder();
+ $definition = $container->register('foo', CallableClass::class);
+ $definition->addMethodCall('callMethod', [123]);
+
+ (new CheckTypeDeclarationsPass())->process($container);
+
+ $this->addToAssertionCount(1);
+ }
+}
+
+class CallableClass
+{
+ public function __call($name, $arguments)
+ {
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
index 2e5016c623f4d..3ddad62d0e5d7 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
@@ -25,7 +25,9 @@
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedEnumArgumentDummy;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
use Symfony\Component\DependencyInjection\Tests\Fixtures\WithTarget;
use Symfony\Component\DependencyInjection\TypedReference;
@@ -65,6 +67,27 @@ public function testProcess()
$this->assertEquals([['setSensitiveClass', [new Reference('foo')]]], $definition->getMethodCalls());
}
+ /**
+ * @requires PHP 8.1
+ */
+ public function testProcessEnum()
+ {
+ $container = new ContainerBuilder();
+
+ $bindings = [
+ FooUnitEnum::class.' $bar' => new BoundArgument(FooUnitEnum::BAR),
+ ];
+
+ $definition = $container->register(NamedEnumArgumentDummy::class, NamedEnumArgumentDummy::class);
+ $definition->setBindings($bindings);
+
+ $pass = new ResolveBindingsPass();
+ $pass->process($container);
+
+ $expected = [FooUnitEnum::BAR];
+ $this->assertEquals($expected, $definition->getArguments());
+ }
+
public function testUnusedBinding()
{
$this->expectException(InvalidArgumentException::class);
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php
new file mode 100644
index 0000000000000..c172c996a7fb7
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
+
+class NamedEnumArgumentDummy
+{
+ public function __construct(FooUnitEnum $bar)
+ {
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php
index 021b921ec208e..47922be9bde58 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php
@@ -17,6 +17,7 @@
->register('foo', FooClass::class)
->addTag('foo', ['foo' => 'foo'])
->addTag('foo', ['bar' => 'bar', 'baz' => 'baz'])
+ ->addTag('nullable', ['bar' => 'bar', 'baz' => null])
->addTag('foo', ['name' => 'bar', 'baz' => 'baz'])
->setFactory(['Bar\\FooClass', 'getInstance'])
->setArguments(['foo', new Reference('foo.baz'), ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%'], true, new Reference('service_container')])
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml
index ecae10e4051cc..a52d82ac1a3ab 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml
@@ -11,6 +11,7 @@
foo
+
foo
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml
index b202a8d7f681f..a5a10a5a87c43 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml
@@ -14,6 +14,7 @@ services:
- foo: { foo: foo }
- foo: { bar: bar, baz: baz }
- foo: { name: bar, baz: baz }
+ - nullable: { bar: bar, baz: ~ }
arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', foobar: '%foo%' }, true, '@service_container']
properties: { foo: bar, moo: '@foo.baz', qux: { '%foo%': 'foo is %foo%', foobar: '%foo%' } }
calls:
diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php
index 67f1134764f7a..f3c2081042b07 100644
--- a/src/Symfony/Component/DomCrawler/Crawler.php
+++ b/src/Symfony/Component/DomCrawler/Crawler.php
@@ -1158,7 +1158,7 @@ protected function sibling(\DOMNode $node, string $siblingDir = 'nextSibling')
private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument
{
- return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset), [], $charset);
+ return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset));
}
private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument
@@ -1194,11 +1194,11 @@ private function convertToHtmlEntities(string $htmlContent, string $charset = 'U
try {
return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset);
- } catch (\Exception | \ValueError $e) {
+ } catch (\Exception|\ValueError $e) {
try {
$htmlContent = iconv($charset, 'UTF-8', $htmlContent);
$htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8');
- } catch (\Exception | \ValueError $e) {
+ } catch (\Exception|\ValueError $e) {
}
return $htmlContent;
diff --git a/src/Symfony/Component/DomCrawler/FormFieldRegistry.php b/src/Symfony/Component/DomCrawler/FormFieldRegistry.php
index 6e48ec4ceefe3..93522adcb4d52 100644
--- a/src/Symfony/Component/DomCrawler/FormFieldRegistry.php
+++ b/src/Symfony/Component/DomCrawler/FormFieldRegistry.php
@@ -87,8 +87,6 @@ public function &get(string $name)
/**
* Tests whether the form has the given field based on the fully qualified name.
- *
- * @return bool
*/
public function has(string $name): bool
{
diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php
index 774667cef1f8d..f249ca8e3944c 100644
--- a/src/Symfony/Component/Dotenv/Dotenv.php
+++ b/src/Symfony/Component/Dotenv/Dotenv.php
@@ -81,8 +81,8 @@ public function usePutenv(bool $usePutenv = true): self
/**
* Loads one or several .env files.
*
- * @param string $path A file to load
- * @param ...string $extraPaths A list of additional files to load
+ * @param string $path A file to load
+ * @param string[] ...$extraPaths A list of additional files to load
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
@@ -167,8 +167,8 @@ public function bootEnv(string $path, string $defaultEnv = 'dev', array $testEnv
/**
* Loads one or several .env files and enables override existing vars.
*
- * @param string $path A file to load
- * @param ...string $extraPaths A list of additional files to load
+ * @param string $path A file to load
+ * @param string[] ...$extraPaths A list of additional files to load
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
index 6f12185a068ca..dbd2935659d5e 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
@@ -262,8 +262,6 @@ private function formatFile(string $file, int $line, string $text = null): strin
* @param string $file A file path
* @param int $line The selected line number
* @param int $srcContext The number of displayed lines around or -1 for the whole file
- *
- * @return string
*/
private function fileExcerpt(string $file, int $line, int $srcContext = 3): string
{
diff --git a/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php b/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php
index acfb48e76c05c..5707a8355bc90 100644
--- a/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php
+++ b/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php
@@ -30,7 +30,7 @@ class TentativeTypes
'format' => 'string',
'getTimezone' => 'DateTimeZone|false',
'getOffset' => 'int',
- 'getTimestamp' => 'int|false',
+ 'getTimestamp' => 'int',
'diff' => 'DateInterval',
'__wakeup' => 'void',
],
@@ -254,6 +254,7 @@ class TentativeTypes
'isEquivalentTo' => 'bool',
'isLenient' => 'bool',
'isWeekend' => 'bool',
+ 'roll' => 'bool',
'isSet' => 'bool',
'setTime' => 'bool',
'setTimeZone' => 'bool',
diff --git a/src/Symfony/Component/ErrorHandler/Resources/bin/extract-tentative-return-types.php b/src/Symfony/Component/ErrorHandler/Resources/bin/extract-tentative-return-types.php
index a4d2c201c04da..cc98f58b58fa0 100755
--- a/src/Symfony/Component/ErrorHandler/Resources/bin/extract-tentative-return-types.php
+++ b/src/Symfony/Component/ErrorHandler/Resources/bin/extract-tentative-return-types.php
@@ -40,7 +40,7 @@ class TentativeTypes
EOPHP;
-while (false !== $file = fgets(STDIN)) {
+while (false !== $file = fgets(\STDIN)) {
$code = file_get_contents(substr($file, 0, -1));
if (!str_contains($code, '@tentative-return-type')) {
diff --git a/src/Symfony/Component/ErrorHandler/Resources/bin/patch-type-declarations b/src/Symfony/Component/ErrorHandler/Resources/bin/patch-type-declarations
index 4e96448810cd7..efcfcb25daa5a 100755
--- a/src/Symfony/Component/ErrorHandler/Resources/bin/patch-type-declarations
+++ b/src/Symfony/Component/ErrorHandler/Resources/bin/patch-type-declarations
@@ -71,7 +71,7 @@ set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$dep
$exclude = getenv('SYMFONY_PATCH_TYPE_EXCLUDE') ?: null;
foreach ($loader->getClassMap() as $class => $file) {
- if (false !== strpos($file = realpath($file), '/vendor/')) {
+ if (false !== strpos($file = realpath($file), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) {
continue;
}
diff --git a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
index 037810aea799f..f48cc941f8ad3 100644
--- a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
+++ b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
@@ -21,7 +21,7 @@ class RecursiveDirectoryIteratorTest extends IteratorTestCase
public function testRewindOnFtp()
{
try {
- $i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
+ $i = new RecursiveDirectoryIterator('ftp://speedtest:speedtest@ftp.otenet.gr/', \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped('Unsupported stream "ftp".');
}
@@ -37,14 +37,14 @@ public function testRewindOnFtp()
public function testSeekOnFtp()
{
try {
- $i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
+ $i = new RecursiveDirectoryIterator('ftp://speedtest:speedtest@ftp.otenet.gr/', \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped('Unsupported stream "ftp".');
}
$contains = [
- 'ftp://speedtest.tele2.net'.\DIRECTORY_SEPARATOR.'1000GB.zip',
- 'ftp://speedtest.tele2.net'.\DIRECTORY_SEPARATOR.'100GB.zip',
+ 'ftp://speedtest:speedtest@ftp.otenet.gr'.\DIRECTORY_SEPARATOR.'test100Mb.db',
+ 'ftp://speedtest:speedtest@ftp.otenet.gr'.\DIRECTORY_SEPARATOR.'test100k.db',
];
$actual = [];
diff --git a/src/Symfony/Component/Form/Command/DebugCommand.php b/src/Symfony/Component/Form/Command/DebugCommand.php
index a9e3c7661f65f..6979831c32682 100644
--- a/src/Symfony/Component/Form/Command/DebugCommand.php
+++ b/src/Symfony/Component/Form/Command/DebugCommand.php
@@ -277,7 +277,7 @@ private function completeOptions(string $class, CompletionSuggestions $suggestio
if (!class_exists($class) || !is_subclass_of($class, FormTypeInterface::class)) {
$classes = $this->getFqcnTypeClasses($class);
- if (1 === count($classes)) {
+ if (1 === \count($classes)) {
$class = $classes[0];
}
}
diff --git a/src/Symfony/Component/Form/DataAccessorInterface.php b/src/Symfony/Component/Form/DataAccessorInterface.php
index 6c31c8ecdabad..a5b4bc8179ddd 100644
--- a/src/Symfony/Component/Form/DataAccessorInterface.php
+++ b/src/Symfony/Component/Form/DataAccessorInterface.php
@@ -49,8 +49,6 @@ public function setValue(&$viewData, $value, FormInterface $form): void;
*
* @param object|array $viewData The view data of the compound form
* @param FormInterface $form The {@link FormInterface()} instance to check
- *
- * @return bool
*/
public function isReadable($viewData, FormInterface $form): bool;
@@ -62,8 +60,6 @@ public function isReadable($viewData, FormInterface $form): bool;
*
* @param object|array $viewData The view data of the compound form
* @param FormInterface $form The {@link FormInterface()} instance to check
- *
- * @return bool
*/
public function isWritable($viewData, FormInterface $form): bool;
}
diff --git a/src/Symfony/Component/Form/FormView.php b/src/Symfony/Component/Form/FormView.php
index f3f3ba63e1713..0162208e64784 100644
--- a/src/Symfony/Component/Form/FormView.php
+++ b/src/Symfony/Component/Form/FormView.php
@@ -16,8 +16,8 @@
/**
* @author Bernhard Schussek
*
- * @implements \ArrayAccess
- * @implements \IteratorAggregate
+ * @implements \ArrayAccess
+ * @implements \IteratorAggregate
*/
class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
{
@@ -37,7 +37,7 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
/**
* The child views.
*
- * @var array
+ * @var array
*/
public $children = [];
@@ -107,7 +107,7 @@ public function setMethodRendered()
/**
* Returns a child by name (implements \ArrayAccess).
*
- * @param string $name The child name
+ * @param int|string $name The child name
*
* @return self
*/
@@ -120,7 +120,7 @@ public function offsetGet($name)
/**
* Returns whether the given child exists (implements \ArrayAccess).
*
- * @param string $name The child name
+ * @param int|string $name The child name
*
* @return bool
*/
@@ -146,7 +146,7 @@ public function offsetSet($name, $value)
/**
* Removes a child (implements \ArrayAccess).
*
- * @param string $name The child name
+ * @param int|string $name The child name
*
* @return void
*/
@@ -159,7 +159,7 @@ public function offsetUnset($name)
/**
* Returns an iterator to iterate over children (implements \IteratorAggregate).
*
- * @return \ArrayIterator
+ * @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
diff --git a/src/Symfony/Component/Form/Forms.php b/src/Symfony/Component/Form/Forms.php
index f8dc71cbba212..020e75eff7e2c 100644
--- a/src/Symfony/Component/Form/Forms.php
+++ b/src/Symfony/Component/Form/Forms.php
@@ -64,8 +64,6 @@ final class Forms
{
/**
* Creates a form factory with the default configuration.
- *
- * @return FormFactoryInterface
*/
public static function createFormFactory(): FormFactoryInterface
{
@@ -74,8 +72,6 @@ public static function createFormFactory(): FormFactoryInterface
/**
* Creates a form factory builder with the default configuration.
- *
- * @return FormFactoryBuilderInterface
*/
public static function createFormFactoryBuilder(): FormFactoryBuilderInterface
{
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
index 4ed719917549d..4a98eea8eb314 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
@@ -24,7 +24,7 @@
The selected choice is invalid.
- گزینهی انتخابشده نامعتبر است.
+ گزینه انتخاب شده نامعتبر است.
The collection is invalid.
@@ -44,7 +44,7 @@
Please choose a valid date interval.
- لطفاً یک بازهی زمانی معتبر انتخاب کنید.
+ لطفاً یک بازه زمانی معتبر انتخاب کنید.
Please enter a valid date and time.
@@ -124,15 +124,15 @@
Please select a valid option.
- لطفاً یک گزینهی معتبر انتخاب کنید.
+ لطفاً یک گزینه معتبر انتخاب کنید.
Please select a valid range.
- لطفاً یک محدودهی معتبر انتخاب کنید.
+ لطفاً یک محدوده معتبر انتخاب کنید.
Please enter a valid week.
- لطفاً یک هفتهی معتبر وارد کنید.
+ لطفاً یک هفته معتبر وارد کنید.