8000 Merge branch '6.4' into 7.0 · symfony/symfony@7877f70 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7877f70

Browse files
committed
Merge branch '6.4' into 7.0
* 6.4: [VarExporter] Uniform unitialized property error message under ghost and non-ghost objects [AssetMapper] Ignore comment lines in JavaScriptImportPathCompiler Update configuration path in help message [Validator] Review Albanian translation [Process] Fix Inconsistent Exit Status in proc_get_status for PHP Versions Below 8.3 [Validator] Update Czech (cz) translation Sync translations [Mailer][Postmark][Webhook] Make allowed IPs configurable Review portuguese translations [Validator] Fix fields without constraints in `Collection` deal with fields for which no constraints have been configured [DomCrawler] [Form] Fix the exclusion of <template>
2 parents 80f5383 + fadce17 commit 7877f70

File tree

17 files changed

+254
-30
lines changed

17 files changed

+254
-30
lines changed

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,31 @@
2727
*/
2828
final class JavaScriptImportPathCompiler implements AssetCompilerInterface
2929
{
30-
// https://regex101.com/r/qFoeoR/1
31-
private const IMPORT_PATTERN = '/(?:\'(?:[^\'\\\\]|\\\\.)*\'|"(?:[^"\\\\]|\\\\.)*")|(?:import\s*(?:(?:\*\s*as\s+\w+|[\w\s{},*]+)\s*from\s*)?|\bimport\()\s*[\'"`](\.\/[^\'"`]+|(\.\.\/)*[^\'"`]+)[\'"`]\s*[;\)]?/m';
30+
/**
31+
* @see https://regex101.com/r/1iBAIb/1
32+
*/
33+
private const IMPORT_PATTERN = '/
34+
^
35+
(?:\/\/.*) # Lines that start with comments
36+
|
37+
(?:
38+
\'(?:[^\'\\\\]|\\\\.)*\' # Strings enclosed in single quotes
39+
|
40+
"(?:[^"\\\\]|\\\\.)*" # Strings enclosed in double quotes
41+
)
42+
|
43+
(?: # Import statements (script captured)
44+
import\s*
45+
(?:
46+
(?:\*\s*as\s+\w+|\s+[\w\s{},*]+)
47+
\s*from\s*
48+
)?
49+
|
50+
\bimport\(
51+
)
52+
\s*[\'"`](\.\/[^\'"`]+|(\.\.\/)*[^\'"`]+)[\'"`]\s*[;\)]
53+
?
54+
/mx';
3255

3356
public function __construct(
3457
private readonly ImportMapConfigReader $importMapConfigReader,
@@ -42,7 +65,7 @@ public function compile(string $content, MappedAsset $asset, AssetMapperInterfac
4265
return preg_replace_callback(self::IMPORT_PATTERN, function ($matches) use ($asset, $assetMapper, $content) {
4366
$fullImportString = $matches[0][0];
4467

45-
// Ignore enquoted strings (e.g. console.log("import 'foo';")
68+
// Ignore matches that did not capture import statements
4669
if (!isset($matches[1][0])) {
4770
return $fullImportString;
4871
}

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

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

180+
yield 'commented_import_on_one_line_then_module_name_on_next_is_not_ok' => [
181+
'input' => "// import \n './other.js';",
182+
'expectedJavaScriptImports' => [],
183+
];
184+
185+
yield 'commented_import_on_one_line_then_import_on_next_is_ok' => [
186+
'input' => "// import\nimport { Foo } from './other.js';",
187+
'expectedJavaScriptImports' => ['/assets/other.js' => ['lazy' => false, 'asset' => 'other.js', 'add' => true]],
188+
];
189+
180190
yield 'importing_a_css_file_is_included' => [
181191
'input' => "import './styles.css';",
182192
'expectedJavaScriptImports' => ['/assets/styles.css' => ['lazy' => false, 'asset' => 'styles.css', 'add' => true]],

src/Symfony/Component/DomCrawler/Form.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,14 +418,14 @@ private function initialize(): void
418418
// corresponding elements are either descendants or have a matching HTML5 form attribute
419419
$formId = Crawler::xpathLiteral($this->node->getAttribute('id'));
420420

421-
$fieldNodes = $xpath->query(sprintf('( descendant::input[@form=%s] | descendant::button[@form=%1$s] | descendant::textarea[@form=%1$s] | descendant::select[@form=%1$s] | //form[@id=%1$s]//input[not(@form)] | //form[@id=%1$s]//button[not(@form)] | //form[@id=%1$s]//textarea[not(@form)] | //form[@id=%1$s]//select[not(@form)] )[not(ancestor::template)]', $formId));
421+
$fieldNodes = $xpath->query(sprintf('( descendant::input[@form=%s] | descendant::button[@form=%1$s] | descendant::textarea[@form=%1$s] | descendant::select[@form=%1$s] | //form[@id=%1$s]//input[not(@form)] | //form[@id=%1$s]//button[not(@form)] | //form[@id=%1$s]//textarea[not(@form)] | //form[@id=%1$s]//select[not(@form)] )[( not(ancestor::template) or ancestor::turbo-stream )]', $formId));
422422
foreach ($fieldNodes as $node) {
423423
$this->addField($node);
424424
}
425425
} else {
426426
// do the xpath query with $this->node as the context node, to only find descendant elements
427427
// however, descendant elements with form attribute are not part of this form
428-
$fieldNodes = $xpath->query('( descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)] )[not(ancestor::template)]', $this->node);
428+
$fieldNodes = $xpath->query('( descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)] )[( not(ancestor::template) or ancestor::turbo-stream )]', $this->node);
429429
foreach ($fieldNodes as $node) {
430430
$this->addField($node);
431431
}

src/Symfony/Component/DomCrawler/Tests/FormTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ public function testGetValues()
432432
$form = $this->createForm('<form><template><input type="text" name="foo" value="foo" /></template><input type="text" name="bar" value="bar" /><input type="submit" /></form>');
433433
$this->assertEquals(['bar' => 'bar'], $form->getValues(), '->getValues() does not include template fields');
434434
$this->assertFalse($form->has('foo'));
435+
436+
$form = $this->createForm('<turbo-stream><template><form><input type="text" name="foo[bar]" value="foo" /><input type="text" name="bar" value="bar" /><select multiple="multiple" name="baz[]"></select><input type="submit" /></form></template></turbo-stream>');
437+
$this->assertEquals(['foo[bar]' => 'foo', 'bar' => 'bar', 'baz' => []], $form->getValues(), '->getValues() returns all form field values from template field inside a turbo-stream');
435438
}
436439

437440
public function testSetValues()
@@ -486,6 +489,9 @@ public function testGetFiles()
486489
$form = $this->createForm('<form method="post"><template><input type="file" name="foo"/></template><input type="text" name="bar" value="bar"/><input type="submit"/></form>');
487490
$this->assertEquals([], $form->getFiles(), '->getFiles() does not include template file fields');
488491
$this->assertFalse($form->has('foo'));
492+
493+
$form = $this->createForm('<turbo-stream><template><form method="post"><input type="file" name="foo[bar]" /><input type="text" name="bar" value="bar" /><input type="submit" /></form></template></turbo-stream>');
494+
$this->assertEquals(['foo[bar]' => ['name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0]], $form->getFiles(), '->getFiles() return files fields from template inside turbo-stream');
489495
}
490496

491497
public function testGetPhpFiles()

src/Symfony/Component/Form/Resources/translations/validators.sq.xlf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
<header>
55
<note>
66
Për fjalët e huaja, të cilat nuk kanë përkthim të drejtpërdrejtë, ju lutemi të ndiqni rregullat e mëposhtme:
7-
a) në rast se emri është akronim i përdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia gjykohet sipas rastit. Shembull: JSON-i (mashkullore)
8-
b) në rast se emri është akronim i papërdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia është femërore. Shembull: URL-ja (femërore)
9-
c) në rast se emri duhet lakuar për shkak të rasës në fjali, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Shembull: host-i, prej host-it
10-
d) në rast se emri nuk duhet lakuar për shkak të trajtës në fjali, atëherë, emri rrethohet me thonjëzat “”. Shembull: “locale”
7+
a) në rast se emri është akronim i përdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia gjykohet sipas rastit. Shembull: JSON-i (mashkullore)
8+
b) në rast se emri është akronim i papërdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia është femërore. Shembull: URL-ja (femërore)
9+
c) në rast se emri duhet lakuar për shkak të rasës në fjali, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Shembull: host-i, prej host-it
10+
d) në rast se emri nuk duhet lakuar për shkak të trajtës në fjali, atëherë, emri rrethohet me thonjëzat “”. Shembull: “locale”
1111
</note>
1212
</header>
1313
<body>

src/Symfony/Component/Mailer/Bridge/Postmark/Webhook/PostmarkRequestParser.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,18 @@ final class PostmarkRequestParser extends AbstractRequestParser
2727
{
2828
public function __construct(
2929
private readonly PostmarkPayloadConverter $converter,
30+
31+
// https://postmarkapp.com/support/article/800-ips-for-firewalls#webhooks
32+
// localhost is added for testing
33+
private readonly array $allowedIPs = ['3.134.147.250', '50.31.156.6', '50.31.156.77', '18.217.206.57', '127.0.0.1'],
3034
) {
3135
}
3236

3337
protected function getRequestMatcher(): RequestMatcherInterface
3438
{
3539
return new ChainRequestMatcher([
3640
new MethodRequestMatcher('POST'),
37-
// https://postmarkapp.com/support/article/800-ips-for-firewalls#webhooks
38-
// localhost is added for testing
39-
new IpsRequestMatcher(['3.134.147.250', '50.31.156.6', '50.31.156.77', '18.217.206.57', '127.0.0.1']),
41+
new IpsRequestMatcher($this->allowedIPs),
4042
new IsJsonRequestMatcher(),
4143
]);
4244
}

src/Symfony/Component/PasswordHasher/Command/UserPasswordHashCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ protected function configure(): void
6565
Suppose that you have the following security configuration in your application:
6666
6767
<comment>
68-
# app/config/security.yml
68+
# config/packages/security.yml
6969
security:
7070
password_hashers:
7171
Symfony\Component\Security\Core\User\InMemoryUser: plaintext

src/Symfony/Component/Process/Process.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class Process implements \IteratorAggregate
8080
private WindowsPipes|UnixPipes $processPipes;
8181

8282
private ?int $latestSignal = null;
83+
private ?int $cachedExitCode = null;
8384

8485
private static ?bool $sigchild = null;
8586

@@ -1280,6 +1281,19 @@ protected function updateStatus(bool $blocking): void
12801281
$this->processInformation = proc_get_status($this->process);
12811282
$running = $this->processInformation['running'];
12821283

1284+
// In PHP < 8.3, "proc_get_status" only returns the correct exit status on the first call.
1285+
// Subsequent calls return -1 as the process is discarded. This workaround caches the first
1286+
// retrieved exit status for consistent results in later calls, mimicking PHP 8.3 behavior.
1287+
if (\PHP_VERSION_ID < 80300) {
1288+
if (!isset($this->cachedExitCode) && !$running && -1 !== $this->processInformation['exitcode']) {
1289+
$this->cachedExitCode = $this->processInformation['exitcode'];
1290+
}
1291+
1292+
if (isset($this->cachedExitCode) && !$running && -1 === $this->processInformation['exitcode']) {
1293+
$this->processInformation['exitcode'] = $this->cachedExitCode;
1294+
}
1295+
}
1296+
12831297
$this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
12841298

12851299
if ($this->fallbackStatus && $this->isSigchildEnabled()) {

src/Symfony/Component/Process/Tests/ProcessTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,60 @@ public function testEnvCaseInsensitiveOnWindows()
15531553
}
15541554
}
15551555

1556+
public function testMultipleCallsToProcGetStatus()
1557+
{
1558+
$process = $this->getProcess('echo foo');
1559+
$process->start(static function () use ($process) {
1560+
return $process->isRunning();
1561+
});
1562+
while ($process->isRunning()) {
1563+
usleep(1000);
1564+
}
1565+
$this->assertSame(0, $process->getExitCode());
1566+
}
1567+
1568+
public function testFailingProcessWithMultipleCallsToProcGetStatus()
1569+
{
1570+
$process = $this->getProcess('exit 123');
1571+
$process->start(static function () use ($process) {
1572+
return $process->isRunning();
1573+
});
1574+
while ($process->isRunning()) {
1575+
usleep(1000);
1576+
}
1577+
$this->assertSame(123, $process->getExitCode());
1578+
}
1579+
1580+
/**
1581+
* @group slow
1582+
*/
1583+
public function testLongRunningProcessWithMultipleCallsToProcGetStatus()
1584+
{
1585+
$process = $this->getProcess('php -r "sleep(1); echo \'done\';"');
1586+
$process->start(static function () use ($process) {
1587+
return $process->isRunning();
1588+
});
1589+
while ($process->isRunning()) {
1590+
usleep(1000);
1591+
}
1592+
$this->assertSame(0, $process->getExitCode());
1593+
}
1594+
1595+
/**
1596+
* @group slow
1597+
*/
1598+
public function testLongRunningProcessWithMultipleCallsToProcGetStatusError()
1599+
{
1600+
$process = $this->getProcess('php -r "sleep(1); echo \'failure\'; exit(123);"');
1601+
$process->start(static function () use ($process) {
1602+
return $process->isRunning();
1603+
});
1604+
while ($process->isRunning()) {
1605+
usleep(1000);
1606+
}
1607+
$this->assertSame(123, $process->getExitCode());
1608+
}
1609+
15561610
/**
15571611
* @group transient-on-windows
15581612
*/

src/Symfony/Component/Validator/Constraints/Collection.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class Collection extends Composite
3535

3636
public function __construct(?array $fields = null, ?array $groups = null, mixed $payload = null, ?bool $allowExtraFields = null, ?bool $allowMissingFields = null, ?string $extraFieldsMessage = null, ?string $missingFieldsMessage = null)
3737
{
38-
if (\is_array($fields) && ([] === $fields || ($firstField = reset($fields)) instanceof Constraint || ($firstField[0] ?? null) instanceof Constraint)) {
38+
if (self::isFieldsOption($fields)) {
3939
$fields = ['fields' => $fields];
4040
}
4141

@@ -73,4 +73,31 @@ protected function getCompositeOption(): string
7373
{
7474
return 'fields';
7575
}
76+
77+
private static function isFieldsOption($options): bool
78+
{
79+
if (!\is_array($options)) {
80+
return false;
81+
}
82+
83+
foreach ($options as $optionOrField) {
84+
if ($optionOrField instanceof Constraint) {
85+
return true;
86+
}
87+
88+
if (null === $optionOrField) {
89+
continue;
90+
}
91+
92+
if (!\is_array($optionOrField)) {
93+
return false;
94+
}
95+
96+
if ($optionOrField && !($optionOrField[0] ?? null) instanceof Constraint) {
97+
return false;
98+
}
99+
}
100+
101+
return true;
102+
}
76103
}

src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@
136136
</trans-unit>
137137
<trans-unit id="37" resname="This is not a valid IP address.">
138138
<source>This value is not a valid IP address.</source>
139-
<target state="needs-review-translation">Tato hodnota není platnou IP adresou.</target>
139+
<target>Tato hodnota není platnou IP adresou.</target>
140140
</trans-unit>
141141
<trans-unit id="38">
142142
<source>This value is not a valid language.</source>
@@ -192,7 +192,7 @@
192192
</trans-unit>
193193
<trans-unit id="51" resname="No temporary folder was configured in php.ini.">
194194
<source>No temporary folder was configured in php.ini, or the configured folder does not exist.</source>
195-
<target state="needs-review-translation">V php.ini nebyla nastavena cesta k dočasnému adresáři, nebo nastavený adresář neexistuje.</target>
195+
<target>V php.ini nebyla nastavena cesta k dočasnému adresáři, nebo nastavený adresář neexistuje.</target>
196196
</trans-unit>
197197
<trans-unit id="52">
198198
<source>Cannot write temporary file to disk.</source>
@@ -224,7 +224,7 @@
224224
</trans-unit>
225225
<trans-unit id="59" resname="This is not a valid International Bank Account Number (IBAN).">
226226
<source>This value is not a valid International Bank Account Number (IBAN).</source>
227-
<target state="needs-review-translation">Tato hodnota není platným Mezinárodním bankovním číslem účtu (IBAN).</target>
227+
<target>Tato hodnota není platným Mezinárodním bankovním číslem účtu (IBAN).</target>
228228
</trans-unit>
229229
<trans-unit id="60">
230230
<source>This value is not a valid ISBN-10.</source>
@@ -312,15 +312,15 @@
312312
</trans-unit>
313313
<trans-unit id="81" resname="This is not a valid Business Identifier Code (BIC).">
314314
<source>This value is not a valid Business Identifier Code (BIC).</source>
315-
<target state="needs-review-translation">Tato hodnota není platným Kódem obchodního identifikátoru (BIC).</target>
315+
<target>Tato hodnota není platným Kódem obchodního identifikátoru (BIC).</target>
316316
</trans-unit>
317317
<trans-unit id="82">
318318
<source>Error</source>
319319
<target>Chyba</target>
320320
</trans-unit>
321321
<trans-unit id="83" resname="This is not a valid UUID.">
322322
<source>This value is not a valid UUID.</source>
323-
<target state="needs-review-translation">Tato hodnota není platným UUID.</target>
323+
<target>Tato hodnota není platným UUID.</target>
324324
</trans-unit>
325325
<trans-unit id="84">
326326
<source>This value should be a multiple of {{ compared_value }}.</source>
@@ -436,7 +436,7 @@
436436
</trans-unit>
437437
<trans-unit id="112">
438438
<source>This value is not a valid MAC address.</source>
439-
<target state="needs-review-translation">Tato hodnota není platnou MAC adresou.</target>
439+
<target>Tato hodnota není platnou MAC adresou.</target>
440440
</trans-unit>
441441
</body>
442442
</file>

0 commit comments

Comments
 (0)
0