Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3783b01

Browse files
Merge branch '7.4' into 8.0
* 7.4: [HttpClient] Suggest amphp/http-client v5 by default [Security] conflict with event-subscriber v8 Fix leftover [WebProfilerBundle] Fix typos in routing config deprecation messages cs tweak [FrameworkBundle] ensureKernelShutdown in tearDownAfterClass Revert "bug symfony#60564 [FrameworkBundle] ensureKernelShutdown in tearDownAfterClass (cquintana92)" [Security] Keep roles when serializing tokens [JsonPath] Always use brackets notation with `JsonPath::key()`
2 parents 789cf64 + c35e218 commit 3783b01

File tree

9 files changed

+150
-35
lines changed

9 files changed

+150
-35
lines changed

src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Test;
1313

14-
use PHPUnit\Framework\Attributes\AfterClass;
1514
use PHPUnit\Framework\TestCase;
1615
use Symfony\Component\DependencyInjection\Container;
1716
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
@@ -40,6 +39,14 @@ protected function tearDown(): void
4039
static::$booted = false;
4140
}
4241

42+
public static function tearDownAfterClass(): void
43+
{
44+
static::ensureKernelShutdown();
45+
static::$class = null;
46+
static::$kernel = null;
47+
static::$booted = false;
48+
}
49+
4350
/**
4451
* @throws \RuntimeException
4552
* @throws \LogicException
@@ -113,11 +120,8 @@ protected static function createKernel(array $options = []): KernelInterface
113120

114121
/**
115122
* Shuts the kernel down if it was used in the test - called by the tearDown method by default.
116-
*
117-
* @afterClass
118123
*/
119-
#[AfterClass]
120-
public static function ensureKernelShutdown()
124+
protected static function ensureKernelShutdown()
121125
{
122126
if (null !== static::$kernel) {
123127
static::$kernel->boot();

src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/profiler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
foreach (debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT) as $trace) {
1717
if (isset($trace['object']) && $trace['object'] instanceof XmlFileLoader && 'doImport' === $trace['function']) {
1818
if (__DIR__ === dirname(realpath($trace['args'][3]))) {
19-
trigger_deprecation('symfony/routing', '7.3', 'The "profiler.xml" routing configuration file is deprecated, import "profile.php" instead.');
19+
trigger_deprecation('symfony/routing', '7.3', 'The "profiler.xml" routing configuration file is deprecated, import "profiler.php" instead.');
2020

2121
break;
2222
}

src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/wdt.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
foreach (debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT) as $trace) {
1717
if (isset($trace['object']) && $trace['object'] instanceof XmlFileLoader && 'doImport' === $trace['function']) {
1818
if (__DIR__ === dirname(realpath($trace['args'][3]))) {
19-
trigger_deprecation('symfony/routing', '7.3', 'The "xdt.xml" routing configuration file is deprecated, import "xdt.php" instead.');
19+
trigger_deprecation('symfony/routing', '7.3', 'The "wdt.xml" routing configuration file is deprecated, import "wdt.php" instead.');
2020

2121
break;
2222
}

src/Symfony/Component/HttpClient/AmpHttpClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
use Symfony\Contracts\Service\ResetInterface;
3434

3535
if (!interface_exists(DelegateHttpClient::class)) {
36-
throw new \LogicException('You cannot use "Symfony\Component\HttpClient\AmpHttpClient" as the "amphp/http-client" package is not installed. Try running "composer require amphp/http-client:^4.2.1".');
36+
throw new \LogicException('You cannot use "Symfony\Component\HttpClient\AmpHttpClient" as the "amphp/http-client" package is not installed. Try running "composer require amphp/http-client:^5".');
3737
}
3838

3939
/**

src/Symfony/Component/HttpClient/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
"require-dev": {
3232
"amphp/http-client": "^4.2.1|^5.0",
3333
"amphp/http-tunnel": "^1.0|^2.0",
34-
"amphp/socket": "^1.1",
3534
"guzzlehttp/promises": "^1.4|^2.0",
3635
"nyholm/psr7": "^1.0",
3736
"php-http/httplug": "^1.0|^2.0",
@@ -46,6 +45,7 @@
4645
},
4746
"conflict": {
4847
"amphp/amp": "<2.5",
48+
"amphp/socket": "<1.1",
4949
"php-http/discovery": "<1.15"
5050
},
5151
"autoload": {

src/Symfony/Component/JsonPath/JsonPath.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ public function __construct(
3030

3131
public function key(string $key): static
3232
{
33-
return new self($this->path.(str_ends_with($this->path, '..') ? '' : '.').$key);
33+
$escaped = $this->escapeKey($key);
34+
35+
return new self($this->path.'["'.$escaped.'"]');
3436
}
3537

3638
public function index(int $index): static
@@ -80,4 +82,25 @@ public function __toString(): string
8082
{
8183
return $this->path;
8284
}
85+
86+
private function escapeKey(string $key): string
87+
{
88+
$key = strtr($key, [
89+
'\\' => '\\\\',
90+
'"' => '\\"',
91+
"\n" => '\\n',
92+
"\r" => '\\r',
93+
"\t" => '\\t',
94+
"\b" => '\\b',
95+
"\f" => '\\f'
96+
]);
97+
98+
for ($i = 0; $i <= 31; $i++) {
99+
if ($i < 8 || $i > 13) {
100+
$key = str_replace(chr($i), sprintf('\\u%04x', $i), $key);
101+
}
102+
}
103+
104+
return $key;
105+
}
83106
}

src/Symfony/Component/JsonPath/Tests/JsonCrawlerTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ public function testAllAuthors()
4949
], $result);
5050
}
5151

52+
public function testAllAuthorsWithBrackets()
53+
{
54+
$result = self::getBookstoreCrawler()->find('$..["author"]');
55+
56+
$this->assertCount(4, $result);
57+
$this->assertSame([
58+
'Nigel Rees',
59+
'Evelyn Waugh',
60+
'Herman Melville',
61+
'J. R. R. Tolkien',
62+
], $result);
63+
}
64+
5265
public function testAllThingsInStore()
5366
{
5467
$result = self::getBookstoreCrawler()->find('$.store.*');
@@ -58,6 +71,15 @@ public function testAllThingsInStore()
5871
$this->assertArrayHasKey('color', $result[1]);
5972
}
6073

74+
public function testAllThingsInStoreWithBrackets()
75+
{
76+
$result = self::getBookstoreCrawler()->find('$["store"][*]');
77+
78+
$this->assertCount(2, $result);
79+
$this->assertCount(4, $result[0]);
80+
$this->assertArrayHasKey('color', $result[1]);
81+
}
82+
6183
public function testEscapedDoubleQuotesInFieldName()
6284
{
6385
$crawler = new JsonCrawler(<<<JSON
@@ -77,6 +99,14 @@ public function testBasicNameSelector()
7799
$this->assertSame('Nigel Rees', $result[0]['author']);
78100
}
79101

102+
public function testBasicNameSelectorWithBrackts()
103+
{
104+
$result = self::getBookstoreCrawler()->find('$["store"]["book"]')[0];
105+
106+
$this->assertCount(4, $result);
107+
$this->assertSame('Nigel Rees', $result[0]['author']);
108+
}
109+
80110
public function testAllPrices()
81111
{
82112
$result = self::getBookstoreCrawler()->find('$.store..price');
@@ -121,6 +151,17 @@ public function testBooksWithIsbn()
121151
], [$result[0]['isbn'], $result[1]['isbn']]);
122152
}
123153

154+
public function testBooksWithBracketsAndFilter()
155+
{
156+
$result = self::getBookstoreCrawler()->find('$..["book"][?(@.isbn)]');
157+
158+
$this->assertCount(2, $result);
159+
$this->assertSame([
160+
'0-553-21311-3',
161+
'0-395-19395-8',
162+
], [$result[0]['isbn'], $result[1]['isbn']]);
163+
}
164+
124165
public function testBooksLessThanTenDollars()
125166
{
126167
$result = self::getBookstoreCrawler()->find('$..book[?(@.price < 10)]');
@@ -216,6 +257,14 @@ public function testEverySecondElementReverseSlice()
216257
$this->assertSame([6, 2, 5], $result);
217258
}
218259

260+
public function testEverySecondElementReverseSliceAndBrackets()
261+
{
262+
$crawler = self::getSimpleCollectionCrawler();
263+
264+
$result = $crawler->find('$["a"][::-2]');
265+
$this->assertSame([6, 2, 5], $result);
266+
}
267+
219268
public function testEmptyResults()
220269
{
221270
$crawler = self::getSimpleCollectionCrawler();
@@ -404,6 +453,19 @@ public function testAcceptsJsonPath()
404453
$this->assertSame('red', $result[0]['color']);
405454
}
406455

456+
public function testStarAsKey()
457+
{
458+
$crawler = new JsonCrawler(<<<JSON
459+
{"*": {"a": 1, "b": 2}, "something else": {"c": 3}}
460+
JSON);
461+
462+
$result = $crawler->find('$["*"]');
463+
464+
$this->assertCount(1, $result);
465+
$this->assertSame(['a' => 1, 'b' => 2], $result[0]);
466+
}
467+
468+
407469
private static function getBookstoreCrawler(): JsonCrawler
408470
{
409471
return new JsonCrawler(<<<JSON

src/Symfony/Component/JsonPath/Tests/JsonPathTest.php

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public function testBuildPath()
2323
->index(0)
2424
->key('address');
2525

26-
$this->assertSame('$.users[0].address', (string) $path);
27-
$this->assertSame('$.users[0].address..city', (string) $path->deepScan()->key('city'));
26+
$this->assertSame('$["users"][0]["address"]', (string) $path);
27+
$this->assertSame('$["users"][0]["address"]..["city"]', (string) $path->deepScan()->key('city'));
2828
}
2929

3030
public function testBuildWithFilter()
@@ -33,7 +33,7 @@ public function testBuildWithFilter()
3333
$path = $path->key('users')
3434
->filter('@.age > 18');
3535

36-
$this->assertSame('$.users[?(@.age > 18)]', (string) $path);
36+
$this->assertSame('$["users"][?(@.age > 18)]', (string) $path);
3737
}
3838

3939
public function testAll()
@@ -42,7 +42,7 @@ public function testAll()
4242
$path = $path->key('users')
4343
->all();
4444

45-
$this->assertSame('$.users[*]', (string) $path);
45+
$this->assertSame('$["users"][*]', (string) $path);
4646
}
4747

4848
public function testFirst()
@@ -51,7 +51,7 @@ public function testFirst()
5151
$path = $path->key('users')
5252
->first();
5353

54-
$this->assertSame('$.users[0]', (string) $path);
54+
$this->assertSame('$["users"][0]', (string) $path);
5555
}
5656

5757
public function testLast()
@@ -60,6 +60,47 @@ public function testLast()
6060
$path = $path->key('users')
6161
->last();
6262

63-
$this->assertSame('$.users[-1]', (string) $path);
63+
$this->assertSame('$["users"][-1]', (string) $path);
64+
}
65+
66+
/**
67+
* @dataProvider provideKeysToEscape
68+
*/
69+
public function testEscapedKey(string $key, string $expectedPath)
70+
{
71+
$path = new JsonPath();
72+
$path = $path->key($key);
73+
74+
$this->assertSame($expectedPath, (string) $path);
75+
}
76+
77+
public static function provideKeysToEscape(): iterable
78+
{
79+
yield ['simple_key', '$["simple_key"]'];
80+
yield ['key"with"quotes', '$["key\\"with\\"quotes"]'];
81+
yield ['path\\backslash', '$["path\\backslash"]'];
82+
yield ['mixed\\"case', '$["mixed\\\\\\"case"]'];
83+
yield ['unicode_🔑', '$["unicode_🔑"]'];
84+
yield ['"quotes_only"', '$["\\"quotes_only\\""]'];
85+
yield ['\\\\multiple\\\\backslashes', '$["\\\\\\\\multiple\\\\\\backslashes"]'];
86+
yield ["control\x00\x1f\x1echar", '$["control\u0000\u001f\u001echar"]'];
87+
88+
yield ['key"with\\"mixed', '$["key\\"with\\\\\\"mixed"]'];
89+
yield ['\\"complex\\"case\\"', '$["\\\\\\"complex\\\\\\"case\\\\\\""]'];
90+
yield ['json_like":{"value":"test"}', '$["json_like\\":{\\"value\\":\\"test\\"}"]'];
91+
yield ['C:\\Program Files\\"App Name"', '$["C:\\\\Program Files\\\\\\"App Name\\""]'];
92+
93+
yield ['key_with_é_accents', '$["key_with_é_accents"]'];
94+
yield ['unicode_→_arrows', '$["unicode_→_arrows"]'];
95+
yield ['chinese_中文_key', '$["chinese_中文_key"]'];
96+
97+
yield ['', '$[""]'];
98+
yield [' ', '$[" "]'];
99+
yield [' spaces ', '$[" spaces "]'];
100+
yield ["\t\n\r", '$["\\t\\n\\r"]'];
101+
yield ["control\x00char", '$["control\u0000char"]'];
102+
yield ["newline\nkey", '$["newline\\nkey"]'];
103+
yield ["tab\tkey", '$["tab\\tkey"]'];
104+
yield ["carriage\rreturn", '$["carriage\\rreturn"]'];
64105
}
65106
}

src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,12 @@ abstract class AbstractToken implements TokenInterface, \Serializable
3232
*/
3333
public function __construct(array $roles = [])
3434
{
35-
$this->roleNames = [];
36-
37-
foreach ($roles as $role) {
38-
$this->roleNames[] = (string) $role;
39-
}
35+
$this->roleNames = $roles;
4036
}
4137

4238
public function getRoleNames(): array
4339
{
44-
return $this->roleNames ??= self::__construct($this->user->getRoles()) ?? $this->roleNames;
40+
return $this->roleNames ??= $this->user?->getRoles() ?? [];
4541
}
4642

4743
public function getUserIdentifier(): string
@@ -90,13 +86,7 @@ public function eraseCredentials(): void
9086
*/
9187
public function __serialize(): array
9288
{
93-
$data = [$this->user, true, null, $this->attributes];
94-
95-
if (!$this->user instanceof EquatableInterface) {
96-
$data[] = $this->roleNames;
97-
}
98-
99-
return $data;
89+
return [$this->user, true, null, $this->attributes, $this->getRoleNames()];
10090
}
10191

10292
/**
@@ -160,12 +150,7 @@ public function __toString(): string
160150
$class = static::class;
161151
$class = substr($class, strrpos($class, '\\') + 1);
162152

163-
$roles = [];
164-
foreach ($this->roleNames as $role) {
165-
$roles[] = $role;
166-
}
167-
168-
return \sprintf('%s(user="%s", roles="%s")', $class, $this->getUserIdentifier(), implode(', ', $roles));
153+
return \sprintf('%s(user="%s", roles="%s")', $class, $this->getUserIdentifier(), implode(', ', $this->getRoleNames()));
169154
}
170155

171156
/**

0 commit comments

Comments
 (0)