8000 Merge branch '5.1' · symfony/symfony@78f4a9f · GitHub
[go: up one dir, main page]

Skip to content

Commit 78f4a9f

Browse files
committed
Merge branch '5.1'
* 5.1: Fix for issue #37681 Revert changes to Table->fillCells() [Console] Table: support cells with newlines after a cell with colspan >= 2 Fix redis connect with empty password [Validator] Add BC layer for notInRangeMessage when min and max are set
2 parents d2b5ee0 + 806ef94 commit 78f4a9f

File tree

12 files changed

+470
-7
lines changed

12 files changed

+470
-7
lines changed

src/Symfony/Component/Cache/Traits/RedisTrait.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ public static function createConnection($dsn, array $options = [])
103103
$params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) {
104104
if (isset($m[2])) {
105105
$auth = $m[2];
106+
107+
if ('' === $auth) {
108+
$auth = null;
109+
}
106110
}
107111

108112
return 'file:'.($m[1] ?? '');

src/Symfony/Component/Console/Helper/Table.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,9 @@ private function buildTableRows(array $rows): TableRows
562562
if (0 === $lineKey) {
563563
$rows[$rowKey][$column] = $line;
564564
} else {
565+
if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
566+
$unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
567+
}
565568
$unmergedRows[$rowKey][$lineKey][$column] = $line;
566569
}
567570
}
@@ -573,8 +576,8 @@ private function buildTableRows(array $rows): TableRows
573576
yield $this->fillCells($row);
574577

575578
if (isset($unmergedRows[$rowKey])) {
576-
foreach ($unmergedRows[$rowKey] as $row) {
577-
yield $row;
579+
foreach ($unmergedRows[$rowKey] as $unmergedRow) {
580+
yield $this->fillCells($unmergedRow);
578581
}
579582
}
580583
}
@@ -658,6 +661,7 @@ private function fillNextRows(array $rows, int $line): array
658661
private function fillCells($row)
659662
{
660663
$newRow = [];
664+
661665
foreach ($row as $column => $cell) {
662666
$newRow[] = $cell;
663667
if ($cell instanceof TableCell && $cell->getColspan() > 1) {

src/Symfony/Component/Console/Tests/Helper/TableTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,45 @@ public function renderProvider()
333333
| Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil! |
334334
+-------------------------------+-------------------------------+-----------------------------+
335335

336+
TABLE
337+
],
338+
'Cell after colspan contains new line break' => [
339+
['Foo', 'Bar', 'Baz'],
340+
[
341+
[
342+
new TableCell("foo\nbar", ['colspan' => 2]),
343+
"baz\nqux",
344+
],
345+
],
346+
'default',
347+
<<<'TABLE'
348+
+-----+-----+-----+
349+
| Foo | Bar | Baz |
350+
+-----+-----+-----+
351+
| foo | baz |
352+
| bar | qux |
353+
+-----+-----+-----+
354+
355+
TABLE
356+
],
357+
'Cell after colspan contains multiple new lines' => [
358+
['Foo', 'Bar', 'Baz'],
359+
[
360+
[
361+
new TableCell("foo\nbar", ['colspan' => 2]),
362+
"baz\nqux\nquux",
363+
],
364+
],
365+
'default',
366+
<<<'TABLE'
367+
+-----+-----+------+
368+
| Foo | Bar | Baz |
369+
+-----+-----+------+
370+
| foo | baz |
371+
| bar | qux |
372+
| | quux |
373+
+-----+-----+------+
374+
336375
TABLE
337376
],
338377
'Cell with rowspan' => [

src/Symfony/Component/DomCrawler/Crawler.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,7 @@ public function addContent(string $content, string $type = null)
182182
*/
183183
public function addHtmlContent(string $content, string $charset = 'UTF-8')
184184
{
185-
// Use HTML5 parser if the content is HTML5 and the library is available
186-
$dom = null !== $this->html5Parser && strspn($content, " \t\r\n") === stripos($content, '<!doctype html>') ? $this->parseHtml5($content, $charset) : $this->parseXhtml($content, $charset);
185+
$dom = $this->parseHtmlString($content, $charset);
187186
$this->addDocument($dom);
188187

189188
$base = $this->filterRelativeXPath('descendant-or-self::base')->extract(['href']);
@@ -1234,4 +1233,35 @@ private function createCssSelectorConverter(): CssSelectorConverter
12341233

12351234
return new CssSelectorConverter($this->isHtml);
12361235
}
1236+
1237+
/**
1238+
* Parse string into DOMDocument object using HTML5 parser if the content is HTML5 and the library is available.
1239+
* Use libxml parser otherwise.
1240+
*/
1241+
private function parseHtmlString(string $content, string $charset): \DOMDocument
1242+
{
1243+
if ($this->canParseHtml5String($content)) {
1244+
return $this->parseHtml5($content, $charset);
1245+
}
1246+
1247+
return $this->parseXhtml($content, $charset);
1248+
}
1249+
1250+
private function canParseHtml5String(string $content): bool
1251+
{
1252+
if (null === $this->html5Parser) {
1253+
return false;
1254+
}
1255+
if (false === ($pos = stripos($content, '<!doctype html>'))) {
1256+
return false;
1257+
}
1258+
$header = substr($content, 0, $pos);
1259+
1260+
return '' === $header || $this->isValidHtml5Heading($header);
1261+
}
1262+
1263+
private function isValidHtml5Heading(string $heading): bool
1264+
{
1265+
return 1 === preg_match('/^\x{FEFF}?\s*(<!--[^>]*?-->\s*)*$/u', $heading);
1266+
}
12371267
}

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,56 @@ public function testAddHtml5()
2525
$crawler->add($this->getDoctype().'<html><body><h1><p>Foo</p></h1></body></html>');
2626
$this->assertEquals('Foo', $crawler->filterXPath('//h1')->text(), '->add() adds nodes from a string');
2727
}
28+
29+
/** @dataProvider validHtml5Provider */
30+
public function testHtml5ParserParseContentStartingWithValidHeading(string $content): void
31+
{
32+
$this->skipTestIfHTML5LibraryNotAvailable();
33+
34+
$crawler = $this->createCrawler();
35+
$crawler->addHtmlContent($content);
36+
self::assertEquals(
37+
'Foo',
38+
$crawler->filterXPath('//h1')->text(),
39+
'->addHtmlContent() parses valid HTML with comment before doctype'
40+
);
41+
}
42+
43+
/** @dataProvider invalidHtml5Provider */
44+
public function testHtml5ParserWithInvalidHeadedContent(string $content): void
45+
{
46+
$this->skipTestIfHTML5LibraryNotAvailable();
47+
48+
$crawler = $this->createCrawler();
49+
$crawler->addHtmlContent($content);
50+
self::assertEmpty($crawler->filterXPath('//h1')->text(), '->addHtmlContent failed as expected');
51+
}
52+
53+
public function validHtml5Provider(): iterable
54+
{
55+
$html = $this->getDoctype().'<html><body><h1><p>Foo</p></h1></body></html>';
56+
$BOM = \chr(0xEF).\chr(0xBB).\chr(0xBF);
57+
58+
yield 'BOM first' => [$BOM.$html];
59+
yield 'Single comment' => ['<!-- comment -->'.$html];
60+
yield 'Multiline comment' => ["<!-- \n multiline comment \n -->".$html];
61+
yield 'Several comments' => ['<!--c--> <!--cc-->'.$html];
62+
yield 'Whitespaces' => [' '.$html];
63+
yield 'All together' => [$BOM.' '.'<!--c-->'.$html];
64+
}
65+
66+
public function invalidHtml5Provider(): iterable
67+
{
68+
$html = $this->getDoctype().'<html><body><h1><p>Foo</p></h1></body></html>';
69+
70+
yield 'Text' => ['hello world'.$html];
71+
yield 'Text between comments' => ['<!--c--> test <!--cc-->'.$html];
72+
}
73+
74+
private function skipTestIfHTML5LibraryNotAvailable(): void
75+
{
76+
if (!class_exists(\Masterminds\HTML5::class)) {
77+
self::markTestSkipped('HTML5 library is not available');
78+
}
79+
}
2880
}

src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,28 @@ public function testAuth()
155155
Connection::fromDsn('redis://password@localhost/queue', [], $redis);
156156
}
157157

158+
public function testNoAuthWithEmptyPassword()
159+
{
160+
$redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
161+
162+
$redis->expects($this->exactly(0))->method('auth')
163+
->with('')
164+
->willThrowException(new \RuntimeException());
165+
166+
Connection::fromDsn('redis://@localhost/queue', [], $redis);
167+
}
168+
169+
public function testAuthZeroPassword()
170+
{
171+
$redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
172+
173+
$redis->expects($this->exactly(1))->method('auth')
174+
->with('0')
175+
->willReturn(true);
176+
177+
Connection::fromDsn('redis://0@localhost/queue', [], $redis);
178+
}
179+
158180
public function testFailedAuth()
159181
{
160182
$this->expectException(\InvalidArgumentException::class);

src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ public function __construct(array $configuration, array $connectionCredentials =
6363
$this->connection->connect($connectionCredentials['host'] ?? '127.0.0.1', $connectionCredentials['port'] ?? 6379);
6464
$this->connection->setOption(\Redis::OPT_SERIALIZER, $redisOptions['serializer'] ?? \Redis::SERIALIZER_PHP);
6565

66-
if (isset($connectionCredentials['auth']) && !$this->connection->auth($connectionCredentials['auth'])) {
66+
$auth = $connectionCredentials['auth'] ?? null;
67+
if ('' === $auth) {
68+
$auth = null;
69+
}
70+
71+
if (null !== $auth && !$this->connection->auth($auth)) {
6772
throw new InvalidArgumentException('Redis connection failed: '.$redis->getLastError());
6873
}
6974

0 commit comments

Comments
 (0)
0