8000 Merge branch '5.4' into 6.0 · symfony/symfony@889de45 · GitHub
[go: up one dir, main page]

Skip to content

Commit 889de45

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: [Translation] [Bridge] [Lokalise] do not export empty strings [Lock] Use platform to identify the PDO driver fix merge [HttpFoundation] Update http messages of statuses 413 and 422 [DependencyInjection] fix support for "new" in initializers on PHP 8.1 added missing trasnlations in Greek add translation for zh_TW 41830 missing translations for serbian sr latn Changed some translations to be more in line with native Serbian language [HttpFoundation] Fix ianaCodesReasonPhrasesProvider to consume a local file Add armenian translation for #41835 Add swedish translation for #41835 Added missing danish translations and fixed typo in validators.da.xlf [FrameworkBundle] Minor improvement - No `array_merge` in loop
2 parents 28bc209 + 054dd25 commit 889de45

26 files changed

+674
-63
lines changed

src/Symfony/Bundle/FrameworkBundle/Routing/Router.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,15 @@ private function resolveParameters(RouteCollection $collection)
130130

131131
$schemes = [];
132132
foreach ($route->getSchemes() as $scheme) {
133-
$schemes = array_merge($schemes, explode('|', $this->resolve($scheme)));
133+
$schemes[] = explode('|', $this->resolve($scheme));
134134
}
135-
$route->setSchemes($schemes);
135+
$route->setSchemes(array_merge([], ...$schemes));
136136

137137
$methods = [];
138138
foreach ($route->getMethods() as $method) {
139-
$methods = array_merge($methods, explode('|', $this->resolve($method)));
139+
$methods[] = explode('|', $this->resolve($method));
140140
}
141-
$route->setMethods($methods);
141+
$route->setMethods(array_merge([], ...$methods));
142142
$route->setCondition($this->resolve($route->getCondition()));
143143
}
144144
}

src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,44 @@ public function testCacheValidityWithContainerParameters($parameter)
553553
}
554554
}
555555

556+
public function testResolvingSchemes()
557+
{
558+
$routes = new RouteCollection();
559+
560+
$route = new Route('/test', [], [], [], '', ['%parameter.http%', '%parameter.https%']);
561+
$routes->add('foo', $route);
562+
563+
$sc = $this->getPsr11ServiceContainer($routes);
564+
$parameters = $this->getParameterBag([
565+
'parameter.http' => 'http',
566+
'parameter.https' => 'https',
567+
]);
568+
569+
$router = new Router($sc, 'foo', [], null, $parameters);
570+
$route = $router->getRouteCollection()->get('foo');
571+
572+
$this->assertEquals(['http', 'https'], $route->getSchemes());
573+
}
574+
575+
public function testResolvingMethods()
576+
{
577+
$routes = new RouteCollection();
578+
579+
$route = new Route('/test', [], [], [], '', [], ['%parameter.get%', '%parameter.post%']);
580+
$routes->add('foo', $route);
581+
582+
$sc = $this->getPsr11ServiceContainer($routes);
583+
$parameters = $this->getParameterBag([
584+
'PARAMETER.GET' => 'GET',
585+
'PARAMETER.POST' => 'POST',
586+
]);
587+
588+
$router = new Router($sc, 'foo', [], null, $parameters);
589+
$route = $router->getRouteCollection()->get('foo');
590+
591+
$this->assertEquals(['GET', 'POST'], $route->getMethods());
592+
}
593+
556594
public function getContainerParameterForRoute()
557595
{
558596
yield 'String' => ['"foo"'];

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class AutowirePass extends AbstractRecursivePass
4040
private ?string $decoratedClass = null;
4141
private ?string $decoratedId = null;
4242
private ?array $methodCalls = null;
43+
private object $defaultArgument;
4344
private ?\Closure $getPreviousValue = null;
4445
private ?int $decoratedMethodIndex = null;
4546
private ?int $decoratedMethodArgumentIndex = null;
@@ -48,6 +49,10 @@ class AutowirePass extends AbstractRecursivePass
4849
public function __construct(bool $throwOnAutowireException = true)
4950
{
5051
$this->throwOnAutowiringException = $throwOnAutowireException;
52+
$this->defaultArgument = new class() {
53+
public $value;
54+
public $names;
55+
};
5156
}
5257

5358
/**
@@ -62,6 +67,7 @@ public function process(ContainerBuilder $container)
6267
$this->decoratedClass = null;
6368
$this->decoratedId = null;
6469
$this->methodCalls = null;
70+
$this->defaultArgument->names = null;
6571
$this->getPreviousValue = null;
6672
$this->decoratedMethodIndex = null;
6773
$this->decoratedMethodArgumentIndex = null;
@@ -156,8 +162,9 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
156162
$this->decoratedId = $decoratedDefinition[1] ?? $this->currentId.'.inner';
157163
}
158164

165 F438 +
$patchedIndexes = [];
166+
159167
foreach ($this->methodCalls as $i => $call) {
160-
$this->decoratedMethodIndex = $i;
161168
[$method, $arguments] = $call;
162169

163170
if ($method instanceof \ReflectionFunctionAbstract) {
@@ -174,13 +181,39 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
174181
}
175182
}
176183

177-
$arguments = $this->autowireMethod($reflectionMethod, $arguments, $checkAttributes);
184+
$arguments = $this->autowireMethod($reflectionMethod, $arguments, $checkAttributes, $i);
178185

179186
if ($arguments !== $call[1]) {
180187
$this->methodCalls[$i][1] = $arguments;
188+
$patchedIndexes[] = $i;
181189
}
182190
}
183191

192+
// use named arguments to skip complex default values
193+
foreach ($patchedIndexes as $i) {
194+
$namedArguments = null;
195+
$arguments = $this->methodCalls[$i][1];
196+
197+
foreach ($arguments as $j => $value) {
198+
if ($namedArguments && !$value instanceof $this->defaultArgument) {
199+
unset($arguments[$j]);
200+
$arguments[$namedArguments[$j]] = $value;
201+
}
202+
if ($namedArguments || !$value instanceof $this->defaultArgument) {
203+
continue;
204+
}
205+
206+
if (\PHP_VERSION_ID >= 80100 && (\is_array($value->value) ? $value->value : \is_object($value->value))) {
207+
unset($arguments[$j]);
208+
$namedArguments = $value->names;
209+
} else {
210+
$arguments[$j] = $value->value;
211+
}
212+
}
213+
214+
$this->methodCalls[$i][1] = $arguments;
215+
}
216+
184217
return $this->methodCalls;
185218
}
186219

@@ -189,16 +222,19 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
189222
*
190223
* @throws AutowiringFailedException
191224
*/
192-
private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes): array
225+
private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes, int $methodIndex): array
193226
{
194227
$class = $reflectionMethod instanceof \ReflectionMethod ? $reflectionMethod->class : $this->currentId;
195228
$method = $reflectionMethod->name;
196229
$parameters = $reflectionMethod->getParameters();
197230
if ($reflectionMethod->isVariadic()) {
198231
array_pop($parameters);
199232
}
233+
$this->defaultArgument->names = new \ArrayObject();
200234

201235
foreach ($parameters as $index => $parameter) {
236+
$this->defaultArgument->names[$index] = $parameter->name;
237+
202238
if (\array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
203239
continue;
204240
}
@@ -236,7 +272,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
236272
// be false when isOptional() returns true. If the
237273
// argument *is* optional, allow it to be missing
238274
if ($parameter->isOptional()) {
239-
continue;
275+
--$index;
276+
break;
240277
}
241278
$type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false);
242279
$type = $type ? sprintf('is type-hinted "%s"', ltrim($type, '\\')) : 'has no type-hint';
@@ -245,7 +282,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
245282
}
246283

247284
// specifically pass the default value
248-
$arguments[$index] = $parameter->getDefaultValue();
285+
$arguments[$index] = clone $this->defaultArgument;
286+
$arguments[$index]->value = $parameter->getDefaultValue();
249287

250288
continue;
251289
}
@@ -255,7 +293,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
255293
$failureMessage = $this->createTypeNotFoundMessageCallback($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
256294

257295
if ($parameter->isDefaultValueAvailable()) {
258-
$value = $parameter->getDefaultValue();
296+
$value = clone $this->defaultArgument;
297+
$value->value = $parameter->getDefaultValue();
259298
} elseif (!$parameter->allowsNull()) {
260299
throw new AutowiringFailedException($this->currentId, $failureMessage);
261300
}
@@ -276,6 +315,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
276315
} else {
277316
$arguments[$index] = new TypedReference($this->decoratedId, $this->decoratedClass);
278317
$this->getPreviousValue = $getValue;
318+
$this->decoratedMethodIndex = $methodIndex;
279319
$this->decoratedMethodArgumentIndex = $index;
280320

281321
continue;
@@ -287,8 +327,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
287327

288328
if ($parameters && !isset($arguments[++$index])) {
289329
while (0 <= --$index) {
290-
$parameter = $parameters[$index];
291-
if (!$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== $arguments[$index]) {
330+
if (!$arguments[$index] instanceof $this->defaultArgument) {
292331
break;
293332
}
294333
unset($arguments[$index]);

src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
3939
}
4040

4141
$i = 0;
42+
$hasNamedArgs = false;
4243
foreach ($value->getArguments() as $k => $v) {
44+
if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
45+
$hasNamedArgs = true;
46+
continue;
47+
}
48+
4349
if ($k !== $i++) {
4450
if (!\is_int($k)) {
4551
$msg = sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k);
@@ -57,11 +63,27 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
5763
throw new RuntimeException($msg);
5864
}
5965
}
66+
67+
if ($hasNamedArgs) {
68+
$msg = sprintf('Invalid constructor argument for service "%s": cannot use positional argument after named argument. Check your service definition.', $this->currentId);
69+
$value->addError($msg);
70+
if ($this->throwExceptions) {
71+
throw new RuntimeException($msg);
72+
}
73+
74+
break;
75+
}
6076
}
6177

6278
foreach ($value->getMethodCalls() as $methodCall) {
6379
$i = 0;
80+
$hasNamedArgs = false;
6481
foreach ($methodCall[1] as $k => $v) {
82+
if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
83+
$hasNamedArgs = true;
84+
continue;
85+
}
86+
6587
if ($k !== $i++) {
6688
if (!\is_int($k)) {
6789
$msg = sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k);
@@ -79,6 +101,16 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
79101
throw new RuntimeException($msg);
80102
}
81103
}
104+
105+
if ($hasNamedArgs) {
106+
$msg = sprintf('Invalid argument for method call "%s" of service "%s": cannot use positional argument after named argument. Check your service definition.', $methodCall[0], $this->currentId);
107+
$value->addError($msg);
108+
if ($this->throwExceptions) {
109+
throw new RuntimeException($msg);
110+
}
111+
112+
break;
113+
}
82114
}
83115
}
84116

src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function process(ContainerBuilder $container)
110110
protected function processValue(mixed $value, bool $isRoot = false): mixed
111111
{
112112
if ($value instanceof ArgumentInterface) {
113-
// Reference found in ArgumentInterface::getValues() are not inlineable
113+
// References found in ArgumentInterface::getValues() are not inlineable
114114
return $value;
115115
}
116116

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,8 @@ private function addServiceMethodCalls(Definition $definition, string $variableN
730730
$calls = '';
731731
foreach ($definition->getMethodCalls() as $k => $call) {
732732
$arguments = [];
733-
foreach ($call[1] as $value) {
734-
$arguments[] = $this->dumpValue($value);
733+
foreach ($call[1] as $i => $value) {
734+
$arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value);
735735
}
736736

737737
$witherAssignation = '';
@@ -1121,8 +1121,8 @@ private function addNewInstance(Definition $definition, string $return = '', str
11211121
}
11221122

11231123
$arguments = [];
1124-
foreach ($definition->getArguments() as $value) {
1125-
$arguments[] = $this->dumpValue($value);
1124+
foreach ($definition->getArguments() as $i => $value) {
1125+
$arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value);
11261126
}
11271127

11281128
if (null !== $definition->getFactory()) {

src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckArgumentsValidityPassTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,22 @@ public function testProcess()
4646
*/
4747
public function testException(array $arguments, array $methodCalls)
4848
{
49-
$this->expectException(RuntimeException::class);
5049
$container = new ContainerBuilder();
5150
$definition = $container->register('foo');
5251
$definition->setArguments($arguments);
5352
$definition->setMethodCalls($methodCalls);
5453

5554
$pass = new CheckArgumentsValidityPass();
55+
$this->expectException(RuntimeException::class);
5656
$pass->process($container);
5757
}
5858

5959
public function definitionProvider()
6060
{
6161
return [
62-
[[null, 'a' => 'a'], []],
62+
[['a' => 'a', null], []],
6363
[[1 => 1], []],
64-
[[], [['baz', [null, 'a' => 'a']]]],
64+
[[], [['baz', ['a' => 'a', null]]]],
6565
[[], [['baz', [1 => 1]]]],
6666
];
6767
}
@@ -70,7 +70,7 @@ public function testNoException()
7070
{
7171
$container = new ContainerBuilder();
7272
$definition = $container->register('foo');
73-
$definition->setArguments([null, 'a' => 'a']);
73+
$definition->setArguments(['a' => 'a', null]);
7474

7575
$pass = new CheckArgumentsValidityPass(false);
7676
$pass->process($container);

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
4646
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
4747
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
48+
use Symfony\Component\DependencyInjection\Tests\Fixtures\NewInInitializer;
4849
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
4950
use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator;
5051
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1;
@@ -1189,6 +1190,24 @@ public function testDumpHandlesObjectClassNames()
11891190
$this->assertInstanceOf(\stdClass::class, $container->get('bar'));
11901191
}
11911192

1193+
/**
1194+
* @requires PHP 8.1
1195+
*/
1196+
public function testNewInInitializer()
1197+
{
1198+
$container = new ContainerBuilder();
1199+
$container
1200+
->register('foo', NewInInitializer::class)
1201+
->setPublic(true)
1202+
->setAutowired(true)
1203+
->setArguments(['$bar' => 234]);
1204+
1205+
$container->compile();
1206+
1207+
$dumper = new PhpDumper($container);
1208+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_new_in_initializer.php', $dumper->dump());
1209+
}
1210+
11921211
/**
11931212
* @requires PHP 8.1
11941213
*/
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
class NewInInitializer
6+
{
7+
public function __construct($foo = new \stdClass(), $bar = 123)
8+
{
9+
}
10+
}

0 commit comments

Comments
 (0)
0