8000 Merge branch '7.1' into 7.2 · symfony/symfony@3ba7a48 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3ba7a48

Browse files
committed
Merge branch '7.1' into 7.2
* 7.1: [AssetMapper] Fix `JavaScriptImportPathCompiler` regex for non-latin characters Definition::$class may not be class-string require Cache component versions compatible with Redis 6.1 [Twitter][Notifier] Fix post INIT upload [Messenger][RateLimiter] fix additional message handled when using a rate limiter [Serializer] Revert default groups [Serializer] fixed object normalizer for a class with `cancel` method Fix bucket size reduce when previously created with bigger size
2 parents 4e682e4 + ffd60b6 commit 3ba7a48

27 files changed

+268
-144
lines changed

src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ final class JavaScriptImportPathCompiler implements AssetCompilerInterface
5050
)
5151
\s*[\'"`](\.\/[^\'"`\n]++|(\.\.\/)*+[^\'"`\n]++)[\'"`]\s*[;\)]
5252
?
53-
/mx';
53+
/mxu';
5454

5555
public function __construct(
5656
private readonly ImportMapConfigReader $importMapConfigReader,

src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,22 @@ public static function provideCompileTests(): iterable
172172
'expectedJavaScriptImports' => ['/assets/other.js' => ['lazy' => false, 'asset' => 'other.js', 'add' => true]],
173173
];
174174

175+
yield 'static_named_import_with_unicode_character' => [
176+
'input' => 'import { ɵmyFunction } from "./other.js";',
177+
'expectedJavaScriptImports' => ['/assets/other.js' => ['lazy' => false, 'asset' => 'other.js', 'add' => true]],
178+
];
179+
180+
yield 'static_multiple_named_imports' => [
181+
'input' => <<<EOF
182+
import {
183+
myFunction,
184+
helperFunction
185+
} from "./other.js";
186+
EOF
187+
,
188+
'expectedJavaScriptImports' => ['/assets/other.js' => ['lazy' => false, 'asset' => 'other.js', 'add' => true]],
189+
];
190+
175191
yield 'static_import_everything' => [
176192
'input' => 'import * as myModule from "./other.js";',
177193
'expectedJavaScriptImports' => ['/assets/other.js' => ['lazy' => false, 'asset' => 'other.js', 'add' => true]],

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,6 @@ public function setClass(?string $class): static
180180

181181
/**
182182
* Gets the service class.
183-
*
184-
* @return class-string|null
185183
*/
186184
public function getClass(): ?string
187185
{

src/Symfony/Component/HttpFoundation/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"require-dev": {
2525
"doctrine/dbal": "^3.6|^4",
2626
"predis/predis": "^1.1|^2.0",
27-
"symfony/cache": "^6.4|^7.0",
27+
"symfony/cache": "^6.4.12|^7.1.5",
2828
"symfony/dependency-injection": "^6.4|^7.0",
2929
"symfony/http-kernel": "^6.4|^7.0",
3030
"symfony/mime": "^6.4|^7.0",
@@ -33,7 +33,7 @@
3333
},
3434
"conflict": {
3535
"doctrine/dbal": "<3.6",
36-
"symfony/cache": "<6.4"
36+
"symfony/cache": "<6.4.12|>=7.0,<7.1.5"
3737
},
3838
"autoload": {
3939
"psr-4": { "Symfony\\Component\\HttpFoundation\\": "" },

src/Symfony/Component/Messenger/Tests/WorkerTest.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
5050
use Symfony\Component\Messenger\Worker;
5151
use Symfony\Component\RateLimiter\RateLimiterFactory;
52+
use Symfony\Component\RateLimiter\Reservation;
5253
use Symfony\Component\RateLimiter\Storage\InMemoryStorage;
5354

5455
/**
@@ -439,21 +440,21 @@ public function testWorkerRateLimitMessages()
439440
$envelope = [
440441
new Envelope(new DummyMessage('message1')),
441442
new Envelope(new DummyMessage('message2')),
443+
new Envelope(new DummyMessage('message3')),
444+
new Envelope(new DummyMessage('message4')),
442445
];
443446
$receiver = new DummyReceiver([$envelope]);
444447

445448
$bus = $this->createMock(MessageBusInterface::class);
446449
$bus->method('dispatch')->willReturnArgument(0);
447450

448451
$eventDispatcher = new EventDispatcher();
449-
$eventDispatcher->addSubscriber(new StopWorkerOnMessageLimitListener(2));
452+
$eventDispatcher->addSubscriber(new StopWorkerOnMessageLimitListener(4));
450453

451454
$rateLimitCount = 0;
452-
$listener = function (WorkerRateLimitedEvent $event) use (&$rateLimitCount) {
455+
$eventDispatcher->addListener(WorkerRateLimitedEvent::class, static function () use (&$rateLimitCount) {
453456
++$rateLimitCount;
454-
$event->getLimiter()->reset(); // Reset limiter to continue test
455-
};
456-
$eventDispatcher->addListener(WorkerRateLimitedEvent::class, $listener);
457+
});
457458

458459
$rateLimitFactory = new RateLimiterFactory([
459460
'id' => 'bus',
@@ -462,11 +463,14 @@ public function testWorkerRateLimitMessages()
462463
'interval' => '1 minute',
463464
], new InMemoryStorage());
464465

466+
ClockMock::register(Reservation::class);
467+
ClockMock::register(InMemoryStorage::class);
468+
465469
$worker = new Worker(['bus' => $receiver], $bus, $eventDispatcher, null, ['bus' => $rateLimitFactory], new MockClock());
466470
$worker->run();
467471

468-
$this->assertCount(2, $receiver->getAcknowledgedEnvelopes());
469-
$this->assertEquals(1, $rateLimitCount);
472+
$this->assertSame(4, $receiver->getAcknowledgeCount());
473+
$this->assertSame(3, $rateLimitCount);
470474
}
471475

472476
public function testWorkerShouldLogOnStop()

src/Symfony/Component/Messenger/Worker.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ private function rateLimit(string $transportName): void
257257

258258
$this->eventDispatcher?->dispatch(new WorkerRateLimitedEvent($rateLimiter, $transportName));
259259
$rateLimiter->reserve()->wait();
260+
$rateLimiter->consume();
260261
}
261262

262263
private function flush(bool $force): bool

src/Symfony/Component/Notifier/Bridge/Twitter/Tests/TwitterTransportTest.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ public function testTweetImage()
6666
$transport = $this->createTransport(new MockHttpClient((function () {
6767
yield function (string $method, string $url, array $options) {
6868
$this->assertSame('POST', $method);
69-
$this->assertSame('https://upload.twitter.com/1.1/media/upload.json?command=INIT&total_bytes=185&media_type=image/gif&media_category=tweet_image', $url);
69+
$this->assertSame('https://upload.twitter.com/1.1/media/upload.json', $url);
70+
$this->assertArrayHasKey('body', $options);
71+
$this->assertSame($options['body'], 'command=INIT&total_bytes=185&media_type=image%2Fgif&media_category=tweet_image');
7072
$this->assertArrayHasKey('authorization', $options['normalized_headers']);
7173

7274
return new MockResponse('{"media_id_string":"gif123"}');
@@ -127,15 +129,19 @@ public function testTweetVideo()
127129
$transport = $this->createTransport(new MockHttpClient((function () {
128130
yield function (string $method, string $url, array $options) {
129131
$this->assertSame('POST', $method);
130-
$this->assertSame('https://upload.twitter.com/1.1/media/upload.json?command=INIT&total_bytes=185&media_type=image/gif&media_category=tweet_video', $url);
132+
$this->assertSame('https://upload.twitter.com/1.1/media/upload.json', $url);
133+
$this->assertArrayHasKey('body', $options);
134+
$this->assertSame($options['body'], 'command=INIT&total_bytes=185&media_type=image%2Fgif&media_category=tweet_video');
131135
$this->assertArrayHasKey('authorization', $options['normalized_headers']);
132136

133137
return new MockResponse('{"media_id_string":"gif123"}');
134138
};
135139

136140
yield function (string $method, string $url, array $options) {
137141
$this->assertSame('POST', $method);
138-
$this->assertSame('https://upload.twitter.com/1.1/media/upload.json?command=INIT&total_bytes=185&media_type=image/gif&media_category=subtitles', $url);
142+
$this->assertSame('https://upload.twitter.com/1.1/media/upload.json', $url);
143+
$this->assertArrayHasKey('body', $options);
144+
$this->assertSame($options['body'], 'command=INIT&total_bytes=185&media_type=image%2Fgif&media_category=subtitles');
139145
$this->assertArrayHasKey('authorization', $options['normalized_headers']);
140146

141147
return new MockResponse('{"media_id_string":"sub234"}');

src/Symfony/Component/Notifier/Bridge/Twitter/TwitterTransport.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,32 +156,32 @@ private function uploadMedia(array $media): array
156156
'category' => $category,
157157
'owners' => $extraOwners,
158158
]) {
159-
$query = [
159+
$body = [
160160
'command' => 'INIT',
161161
'total_bytes' => $file->getSize(),
162162
'media_type' => $file->getContentType(),
163163
];
164164

165165
if ($category) {
166-
$query['media_category'] = $category;
166+
$body['media_category'] = $category;
167167
}
168168

169169
if ($extraOwners) {
170-
$query['additional_owners'] = implode(',', $extraOwners);
170+
$body['additional_owners'] = implode(',', $extraOwners);
171171
}
172172

173173
$pool[++$i] = $this->request('POST', '/1.1/media/upload.json', [
174-
'query' => $query,
174+
'body' => $body,
175175
'user_data' => [$i, null, 0, fopen($file->getPath(), 'r'), $alt, $subtitles],
176176
]);
177177

178178
if ($subtitles) {
179-
$query['total_bytes'] = $subtitles->getSize();
180-
$query['media_type'] = $subtitles->getContentType();
181-
$query['media_category'] = 'subtitles';
179+
$body['total_bytes'] = $subtitles->getSize();
180+
$body['media_type'] = $subtitles->getContentType();
181+
$body['media_category'] = 'subtitles';
182182

183183
$pool[++$i] = $this->request('POST', '/1.1/media/upload.json', [
184-
'query' => $query,
184+
'body' => $body,
185185
'user_data' => [$i, null, 0, fopen($subtitles->getPath(), 'r'), null, $subtitles],
186186
]);
187187
}

src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,11 @@ public function getProperties(string $class, array $context = []): ?array
3838
return null;
3939
}
4040

41-
$groups = $context['serializer_groups'] ?? [];
42-
$groupsHasBeenDefined = [] !== $groups;
43-
$groups = array_merge($groups, ['Default', (false !== $nsSep = strrpos($class, '\\')) ? substr($class, $nsSep + 1) : $class]);
44-
4541
$properties = [];
4642
$serializerClassMetadata = $this->classMetadataFactory->getMetadataFor($class);
4743

4844
foreach ($serializerClassMetadata->getAttributesMetadata() as $serializerAttributeMetadata) {
49-
if (!$serializerAttributeMetadata->isIgnored() && (!$groupsHasBeenDefined || array_intersect(array_merge($serializerAttributeMetadata->getGroups(), ['*']), $groups))) {
45+
if (!$serializerAttributeMetadata->isIgnored() && (null === $context['serializer_groups'] || \in_array('*', $context['serializer_groups'], true) || array_intersect($serializerAttributeMetadata->getGroups(), $context['serializer_groups']))) {
5046
$properties[] = $serializerAttributeMetadata->getName();
5147
}
5248
}

src/Symfony/Component/PropertyInfo/Tests/Extractor/SerializerExtractorTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ public function testGetProperties()
4343
public function testGetPropertiesWithIgnoredProperties()
4444
{
4545
$this->assertSame(['visibleProperty'], $this->extractor->getProperties(IgnorePropertyDummy::class, ['serializer_groups' => ['a']]));
46-
$this->assertSame(['visibleProperty'], $this->extractor->getProperties(IgnorePropertyDummy::class, ['serializer_groups' => ['Default']]));
47-
$this->assertSame(['visibleProperty'], $this->extractor->getProperties(IgnorePropertyDummy::class, ['serializer_groups' => ['IgnorePropertyDummy']]));
4846
}
4947

5048
public function testGetPropertiesWithAnyGroup()

src/Symfony/Component/PropertyInfo/Tests/Fixtures/IgnorePropertyDummy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020
class IgnorePropertyDummy
2121
{
22-
#[Groups(['a', 'Default', 'IgnorePropertyDummy'])]
22+
#[Groups(['a'])]
2323
public $visibleProperty;
2424

2525
#[Groups(['a']), Ignore]

src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation
6767
$now = microtime(true);
6868
$availableTokens = $bucket->getAvailableTokens($now);
6969

70+
if ($availableTokens > $this->maxBurst) {
71+
$availableTokens = $this->maxBurst;
72+
}
73+
7074
if ($availableTokens >= $tokens) {
7175
// tokens are now available, update bucket
7276
$bucket->setTokens($availableTokens - $tokens);

src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ public function testReserveMoreTokensThanBucketSize()
5757
$limiter->reserve(15);
5858
}
5959

60+
public function testReduceBucketSizeWhenAlreadyExistInStorageWithBiggerBucketSize()
61+
{
62+
$limiter = $this->createLimiter(100);
63+
64+
$limiter->consume();
65+
66+
$limiter2 = $this->createLimiter(1);
67+
$limiter2->consume();
68+
69+
$this->assertFalse($limiter2->consume()->isAccepted());
70+
}
71+
6072
public function testReserveMaxWaitingTime()
6173
{
6274
$limiter = $this->createLimiter(10, Rate::perMinute());

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ CHANGELOG
1919

2020
* Add arguments `$class`, `$format` and `$context` to `NameConverterInterface::normalize()` and `NameConverterInterface::denormalize()`
2121
* Add `DateTimeNormalizer::CAST_KEY` context option
22-
* Add `Default` and "class name" default groups
2322
* Add `AbstractNormalizer::FILTER_BOOL` context option
2423
* Add `CamelCaseToSnakeCaseNameConverter::REQUIRE_SNAKE_CASE_PROPERTIES` context option
2524
* Deprecate `AbstractNormalizerContextBuilder::withDefaultContructorArguments(?array $defaultContructorArguments)`, use `withDefaultConstructorArguments(?array $defaultConstructorArguments)` instead (note the missing `s` character in Contructor word in deprecated method)

src/Symfony/Component/Serializer/Mapping/Loader/AttributeLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
115115
}
116116

117117
$accessorOrMutator = preg_match('/^(get|is|has|set)(.+)$/i', $method->name, $matches);
118-
if ($accessorOrMutator) {
118+
if ($accessorOrMutator && !ctype_lower($matches[2][0])) {
119119
$attributeName = lcfirst($matches[2]);
120120

121121
if (isset($attributesMetadata[$attributeName])) {

src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,13 @@ private function getCacheValueForAttributesMetadata(string $class, array $contex
128128
}
129129

130130
$metadataGroups = $metadata->getGroups();
131-
132131
$contextGroups = (array) ($context[AbstractNormalizer::GROUPS] ?? []);
133-
$contextGroupsHasBeenDefined = [] !== $contextGroups;
134-
$contextGroups = array_merge($contextGroups, ['Default', (false !== $nsSep = strrpos($class, '\\')) ? substr($class, $nsSep + 1) : $class]);
135132

136-
if ($contextGroupsHasBeenDefined && !$metadataGroups) {
133+
if ($contextGroups && !$metadataGroups) {
137134
continue;
138135
}
139136

140-
if ($metadataGroups && !array_intersect(array_merge($metadataGroups, ['*']), $contextGroups)) {
137+
if ($metadataGroups && !array_intersect($metadataGroups, $contextGroups) && !\in_array('*', $contextGroups, true)) {
141138
continue;
142139
}
143140

src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,32 +222,27 @@ protected function getAllowedAttributes(string|object $classOrObject, array $con
222222
return false;
223223
}
224224

225-
$classMetadata = $this->classMetadataFactory->getMetadataFor($classOrObject);
226-
$class = $classMetadata->getName();
227-
228225
$groups = $this->getGroups($context);
229-
$groupsHasBeenDefined = [] !== $groups;
230-
$groups = array_merge($groups, ['Default', (false !== $nsSep = strrpos($class, '\\')) ? substr($class, $nsSep + 1) : $class]);
231226

232227
$allowedAttributes = [];
233228
$ignoreUsed = false;
234229

235-
foreach ($classMetadata->getAttributesMetadata() as $attributeMetadata) {
230+
foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
236231
if ($ignore = $attributeMetadata->isIgnored()) {
237232
$ignoreUsed = true;
238233
}
239234

240235
// If you update this check, update accordingly the one in Symfony\Component\PropertyInfo\Extractor\SerializerExtractor::getProperties()
241236
if (
242237
!$ignore
243-
&& (!$groupsHasBeenDefined || array_intersect(array_merge($attributeMetadata->getGroups(), ['*']), $groups))
238+
&& ([] === $groups || \in_array('*', $groups, true) || array_intersect($attributeMetadata->getGroups(), $groups))
244239
&& $this->isAllowedAttribute($classOrObject, $name = $attributeMetadata->getName(), null, $context)
245240
) {
246241
$allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata;
247242
}
248243
}
249244

250-
if (!$ignoreUsed && !$groupsHasBeenDefined && $allowExtraAttributes) {
245+
if (!$ignoreUsed && [] === $groups && $allowExtraAttributes) {
251246
// Backward Compatibility with the code using this method written before the introduction of @Ignore
252247
return false;
253248
}

src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ private function isGetMethod(\ReflectionMethod $method): bool
8787
return !$method->isStatic()
8888
&& !($method->getAttributes(Ignore::class) || $method->getAttributes(LegacyIgnore::class))
8989
&& !$method->getNumberOfRequiredParameters()
90-
&& ((2 < ($methodLength = \strlen($method->name)) && str_starts_with($method->name, 'is'))
91-
|| (3 < $methodLength && (str_starts_with($method->name, 'has') || str_starts_with($method->name, 'get')))
90+
&& ((2 < ($methodLength = \strlen($method->name)) && str_starts_with($method->name, 'is') && !ctype_lower($method->name[2]))
91+
|| (3 < $methodLength && (str_starts_with($method->name, 'has') || str_starts_with($method->name, 'get')) && !ctype_lower($method->name[3]))
9292
);
9393
}
9494

@@ -100,7 +100,9 @@ private function isSetMethod(\ReflectionMethod $method): bool
100100
return !$method->isStatic()
101101
&& !$method->getAttributes(Ignore::class)
102102
&& 0 < $method->getNumberOfParameters()
103-
&& str_starts_with($method->name, 'set');
103+
&& str_starts_with($method->name, 'set')
104+
&& !ctype_lower($method->name[3])
105+
;
104106
}
105107

106108
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array

src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ protected function extractAttributes(object $object, ?string $format = null, arr
8888
$name = $reflMethod->name;
8989
$attributeName = null;
9090

91-
if (3 < \strlen($name) && match ($name[0]) {
91+
// ctype_lower check to find out if method looks like accessor but actually is not, e.g. hash, cancel
92+
if (3 < \strlen($name) && !ctype_lower($name[3]) && match ($name[0]) {
9293
'g' => str_starts_with($name, 'get'),
9394
'h' => str_starts_with($name, 'has'),
9495
'c' => str_starts_with($name, 'can'),
@@ -100,7 +101,7 @@ protected function extractAttributes(object $object, ?string $format = null, arr
100101
if (!$reflClass->hasProperty($attributeName)) {
101102
$attributeName = lcfirst($attributeName);
102103
}
103-
} elseif ('is' !== $name && str_starts_with($name, 'is')) {
104+
} elseif ('is' !== $name && str_starts_with($name, 'is') && !ctype_lower($name[2])) {
104105
// issers
105106
$attributeName = substr($name, 2);
106107

0 commit comments

Comments
 (0)
0