Skip to content

Commit 82d04f6

Browse files
authored
Merge branch 'symfony:6.1' into CASE_INSENSITIVE_FILE_LIST
2 parents 5ca66aa + 7a21a57 commit 82d04f6

31 files changed

+243
-76
lines changed

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ abstract protected function describeCallable(mixed $callable, array $options = [
145145

146146
protected function formatValue(mixed $value): string
147147
{
148+
if ($value instanceof \UnitEnum) {
149+
return ltrim(var_export($value, true), '\\');
150+
}
151+
148152
if (\is_object($value)) {
149153
return sprintf('object(%s)', \get_class($value));
150154
}
@@ -159,15 +163,15 @@ protected function formatValue(mixed $value): string
159163
protected function formatParameter(mixed $value): string
160164
{
161165
if ($value instanceof \UnitEnum) {
162-
return var_export($value, true);
166+
return ltrim(var_export($value, true), '\\');
163167
}
164168

165169
// Recursively search for enum values, so we can replace it
166170
// before json_encode (which will not display anything for \UnitEnum otherwise)
167171
if (\is_array($value)) {
168172
array_walk_recursive($value, static function (&$value) {
169173
if ($value instanceof \UnitEnum) {
170-
$value = var_export($value, true);
174+
$value = ltrim(var_export($value, true), '\\');
171175
}
172176
});
173177
}

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ private function writeData(array $data, array $options)
188188
// before json_encode (which will not display anything for \UnitEnum otherwise)
189189
array_walk_recursive($data, static function (&$value) {
190190
if ($value instanceof \UnitEnum) {
191-
$value = var_export($value, true);
191+
$value = ltrim(var_export($value, true), '\\');
192192
}
193193
});
194194

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
349349
} elseif ($argument instanceof Definition) {
350350
$argumentsInformation[] = 'Inlined Service';
351351
} elseif ($argument instanceof \UnitEnum) {
352-
$argumentsInformation[] = var_export($argument, true);
352+
$argumentsInformation[] = ltrim(var_export($argument, true), '\\');
353353
} elseif ($argument instanceof AbstractArgument) {
354354
$argumentsInformation[] = sprintf('Abstract argument (%s)', $argument->getText());
355355
} else {

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ private function getArgumentNodes(array $arguments, \DOMDocument $dom): array
421421
}
422422
} elseif ($argument instanceof \UnitEnum) {
423423
$argumentXML->setAttribute('type', 'constant');
424-
$argumentXML->appendChild(new \DOMText(var_export($argument, true)));
424+
$argumentXML->appendChild(new \DOMText(ltrim(var_export($argument, true), '\\')));
425425
} else {
426426
$argumentXML->appendChild(new \DOMText($argument));
427427
}

src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
3939
use LoggerAwareTrait;
4040

4141
public const TAGS_PREFIX = "\0tags\0";
42-
private const MAX_NUMBER_OF_KNOWN_TAG_VERSIONS = 1000;
4342

4443
private array $deferred = [];
4544
private AdapterInterface $pool;
@@ -79,8 +78,7 @@ static function (array $items, array $itemTags) {
7978
);
8079
self::$setTagVersions ??= \Closure::bind(
8180
static function (array $items, array $tagVersions) {
82-
$now = null;
83-
foreach ($items as $key => $item) {
81+
foreach ($items as $item) {
8482
$item->newMetadata[CacheItem::METADATA_TAGS] = array_intersect_key($tagVersions, $item->newMetadata[CacheItem::METADATA_TAGS] ?? []);
8583
}
8684
},
@@ -343,14 +341,16 @@ public function __destruct()
343341
private function getTagVersions(array $tagsByKey, bool $persistTags): array
344342
{
345343
$tagVersions = [];
346-
$fetchTagVersions = false;
344+
$fetchTagVersions = $persistTags;
347345

348346
foreach ($tagsByKey as $tags) {
349347
$tagVersions += $tags;
350-
348+
if ($fetchTagVersions) {
349+
continue;
350+
}
351351
foreach ($tags as $tag => $version) {
352352
if ($tagVersions[$tag] !== $version) {
353-
unset($this->knownTagVersions[$tag]);
353+
$fetchTagVersions = true;
354354
}
355355
}
356356
}
@@ -364,14 +364,10 @@ private function getTagVersions(array $tagsByKey, bool $persistTags): array
364364
foreach ($tagVersions as $tag => $version) {
365365
$tags[$tag.static::TAGS_PREFIX] = $tag;
366366
$knownTagVersion = $this->knownTagVersions[$tag] ?? [0, null];
367-
if ($fetchTagVersions || $knownTagVersion[1] !== $version || $now - $knownTagVersion[0] >= $this->knownTagVersionsTtl) {
368-
// reuse previously fetched tag versions up to the ttl
367+
if ($fetchTagVersions || $now > $knownTagVersion[0] || $knownTagVersion[1] !== $version) {
368+
// reuse previously fetched tag versions until the expiration
369369
$fetchTagVersions = true;
370370
}
371-
unset($this->knownTagVersions[$tag]); // For LRU tracking
372-
if ([0, null] !== $knownTagVersion) {
373-
$this->knownTagVersions[$tag] = $knownTagVersion;
374-
}
375371
}
376372

377373
if (!$fetchTagVersions) {
@@ -380,20 +376,24 @@ private function getTagVersions(array $tagsByKey, bool $persistTags): array
380376

381377
$newTags = [];
382378
$newVersion = null;
379+
$expiration = $now + $this->knownTagVersionsTtl;
383380
foreach ($this->tags->getItems(array_keys($tags)) as $tag => $version) {
384-
if (!$version->isHit()) {
381+
unset($this->knownTagVersions[$tag = $tags[$tag]]); // update FIFO
382+
if (null !== $tagVersions[$tag] = $version->get()) {
383+
$this->knownTagVersions[$tag] = [$expiration, $tagVersions[$tag]];
384+
} elseif ($persistTags) {
385385
$newTags[$tag] = $version->set($newVersion ??= random_bytes(6));
386+
$tagVersions[$tag] = $newVersion;
387+
$this->knownTagVersions[$tag] = [$expiration, $newVersion];
386388
}
387-
$tagVersions[$tag = $tags[$tag]] = $version->get();
388-
$this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]];
389389
}
390390

391-
if ($newTags && $persistTags) {
391+
if ($newTags) {
392392
(self::$saveTags)($this->tags, $newTags);
393393
}
394394

395-
if (\count($this->knownTagVersions) > $maxTags = max(self::MAX_NUMBER_OF_KNOWN_TAG_VERSIONS, \count($newTags) << 1)) {
396-
array_splice($this->knownTagVersions, 0, $maxTags >> 1);
395+
while ($now > ($this->knownTagVersions[$tag = array_key_first($this->knownTagVersions)][0] ?? \INF)) {
396+
unset($this->knownTagVersions[$tag]);
397397
}
398398

399399
return $tagVersions;

src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php

Lines changed: 113 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

1414
use PHPUnit\Framework\MockObject\MockObject;
15-
use Psr\Cache\CacheItemInterface;
1615
use Psr\Cache\CacheItemPoolInterface;
1716
use Symfony\Component\Cache\Adapter\AdapterInterface;
1817
use Symfony\Component\Cache\Adapter\ArrayAdapter;
@@ -67,15 +66,18 @@ public function testKnownTagVersionsTtl()
6766

6867
$pool->save($item);
6968
$this->assertTrue($pool->getItem('foo')->isHit());
70-
$this->assertTrue($pool->getItem('foo')->isHit());
7169

72-
sleep(20);
70+
$tagsPool->deleteItem('baz'.TagAwareAdapter::TAGS_PREFIX); // tag invalidation
7371

74-
$this->assertTrue($pool->getItem('foo')->isHit());
72+
$this->assertTrue($pool->getItem('foo')->isHit()); // known tag version is used
7573

76-
sleep(5);
74+
sleep(10);
7775

78-
$this->assertTrue($pool->getItem('foo')->isHit());
76+
$this->assertTrue($pool->getItem('foo')->isHit()); // known tag version is still used
77+
78+
sleep(1);
79+
80+
$this->assertFalse($pool->getItem('foo')->isHit()); // known tag version has expired
7981
}
8082

8183
public function testInvalidateTagsWithArrayAdapter()
@@ -125,4 +127,109 @@ private function getNonPruneableMock(): AdapterInterface&MockObject
125127
{
126128
return $this->createMock(AdapterInterface::class);
127129
}
130+
131+
/**
132+
* @doesNotPerformAssertions
133+
*/
134+
public function testToleranceForStringsAsTagVersionsCase1()
135+
{
136+
$pool = $this->createCachePool();
137+
$adapter = new FilesystemAdapter();
138+
139+
$itemKey = 'foo';
140+
$tag = $adapter->getItem('bar'.TagAwareAdapter::TAGS_PREFIX);
141+
$adapter->save($tag->set("\x00abc\xff"));
142+
$item = $pool->getItem($itemKey);
143+
$pool->save($item->tag('bar'));
144+
$pool->hasItem($itemKey);
145+
$pool->getItem($itemKey);
146+
}
147+
148+
/**
149+
* @doesNotPerformAssertions
150+
*/
151+
public function testToleranceForStringsAsTagVersionsCase2()
152+
{
153+
$pool = $this->createCachePool();
154+
$adapter = new FilesystemAdapter();
155+
156+
$itemKey = 'foo';
157+
$tag = $adapter->getItem('bar'.TagAwareAdapter::TAGS_PREFIX);
158+
$adapter->save($tag->set("\x00abc\xff"));
159+
$item = $pool->getItem($itemKey);
160+
$pool->save($item->tag('bar'));
161+
sleep(100);
162+
$pool->getItem($itemKey);
163+
$pool->hasItem($itemKey);
164+
}
165+
166+
/**
167+
* @doesNotPerformAssertions
168+
*/
169+
public function testToleranceForStringsAsTagVersionsCase3()
170+
{
171+
$pool = $this->createCachePool();
172+
$adapter = new FilesystemAdapter();
173+
174+
$itemKey = 'foo';
175+
$adapter->deleteItem('bar'.TagAwareAdapter::TAGS_PREFIX);
176+
$item = $pool->getItem($itemKey);
177+
$pool->save($item->tag('bar'));
178+
$pool->getItem($itemKey);
179+
180+
$tag = $adapter->getItem('bar'.TagAwareAdapter::TAGS_PREFIX);
181+
$adapter->save($tag->set("\x00abc\xff"));
182+
183+
$pool->hasItem($itemKey);
184+
$pool->getItem($itemKey);
185+
sleep(100);
186+
$pool->getItem($itemKey);
187+
$pool->hasItem($itemKey);
188+
}
189+
190+
/**
191+
* @doesNotPerformAssertions
192+
*/
193+
public function testToleranceForStringsAsTagVersionsCase4()
194+
{
195+
$pool = $this->createCachePool();
196+
$adapter = new FilesystemAdapter();
197+
198+
$itemKey = 'foo';
199+
$tag = $adapter->getItem('bar'.TagAwareAdapter::TAGS_PREFIX);
200+
$adapter->save($tag->set('abcABC'));
201+
202+
$item = $pool->getItem($itemKey);
203+
$pool->save($item->tag('bar'));
204+
205+
$tag = $adapter->getItem('bar'.TagAwareAdapter::TAGS_PREFIX);
206+
$adapter->save($tag->set('001122'));
207+
208+
$pool->invalidateTags(['bar']);
209+
$pool->getItem($itemKey);
210+
}
211+
212+
/**
213+
* @doesNotPerformAssertions
214+
*/
215+
public function testToleranceForStringsAsTagVersionsCase5()
216+
{
217+
$pool = $this->createCachePool();
218+
$pool2 = $this->createCachePool();
219+
$adapter = new FilesystemAdapter();
220+
221+
$itemKey1 = 'foo';
222+
$item = $pool->getItem($itemKey1);
223+
$pool->save($item->tag('bar'));
224+
225+
$tag = $adapter->getItem('bar'.TagAwareAdapter::TAGS_PREFIX);
226+
$adapter->save($tag->set('abcABC'));
227+
228+
$itemKey2 = 'baz';
229+
$item = $pool2->getItem($itemKey2);
230+
$pool2->save($item->tag('bar'));
231+
foreach ($pool->getItems([$itemKey1, $itemKey2]) as $item) {
232+
// run generator
233+
}
234+
}
128235
}

src/Symfony/Component/Config/Resource/GlobResource.php

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -167,28 +167,31 @@ function (\SplFileInfo $file, $path) {
167167
throw new \LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.', $this->pattern));
168168
}
169169

170-
$finder = new Finder();
171170
$regex = Glob::toRegex($this->pattern);
172171
if ($this->recursive) {
173172
$regex = substr_replace($regex, '(/|$)', -2, 1);
174173
}
175174

176175
$prefixLen = \strlen($this->prefix);
177-
foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) {
178-
$normalizedPath = str_replace('\\', '/', $path);
179-
if (!preg_match($regex, substr($normalizedPath, $prefixLen)) || !$info->isFile()) {
180-
continue;
181-
}
182-
if ($this->excludedPrefixes) {
183-
do {
184-
if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) {
185-
continue 2;
186-
}
187-
} while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
188-
}
189176

190-
yield $path => $info;
191-
}
177+
yield from (new Finder())
178+
->followLinks()
179+
->filter(function (\SplFileInfo $info) use ($regex, $prefixLen, $prefix) {
180+
$normalizedPath = str_replace('\\', '/', $info->getPathname());
181+
if (!preg_match($regex, substr($normalizedPath, $prefixLen)) || !$info->isFile()) {
182+
return false;
183+
}
184+
if ($this->excludedPrefixes) {
185+
do {
186+
if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) {
187+
return false;
188+
}
189+
} while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
190+
}
191+
})
192+
->sortByName()
193+
->in($this->prefix)
194+
;
192195
}
193196

194197
private function computeHash(): string

src/Symfony/Component/DependencyInjection/Attribute/InnerService.php renamed to src/Symfony/Component/DependencyInjection/Attribute/MapDecorated.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
namespace Symfony\Component\DependencyInjection\Attribute;
1313

1414
#[\Attribute(\Attribute::TARGET_PARAMETER)]
15-
class InnerService
15+
class MapDecorated
1616
{
1717
}

src/Symfony/Component/DependencyInjection/Attribute/When.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
* @author Nicolas Grekas <p@tchwork.com>
1818
*/
19-
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
19+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
2020
class When
2121
{
2222
public function __construct(

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
6.1
55
---
66

7+
* Add `#[MapDecorated]` attribute telling to which parameter the decorated service should be mapped in a decorator
8+
* Add `#[AsDecorator]` attribute to make a service decorates another
79
* Add `$exclude` to `TaggedIterator` and `TaggedLocator` attributes
810
* Add `$exclude` to `tagged_iterator` and `tagged_locator` configurator
911
* Add an `env` function to the expression language provider

0 commit comments

Comments
 (0)