Skip to content

Commit a02fed5

Browse files
Merge branch '6.4' into 7.2
* 6.4: [Console] Table counts wrong column width when using colspan and `setColumnMaxWidth()` [Console] Table counts wrong number of padding symbols in `renderCell()` method when cell contain unicode variant selector [Cache] Fix using a `ChainAdapter` as an adapter for a pool [Serializer] Fix collect_denormalization_errors flag in defaultContext [VarDumper] Avoid deprecated call in PgSqlCaster Fix command option mode (InputOption::VALUE_REQUIRED) [Uid] Improve entropy of the increment for UUIDv7
2 parents 74dc977 + 5d0df9f commit a02fed5

File tree

18 files changed

+177
-46
lines changed

18 files changed

+177
-46
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ protected function configure(): void
6969
->setDefinition([
7070
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
7171
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
72-
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'The messages domain'),
72+
new InputOption('domain', null, InputOption::VALUE_REQUIRED, 'The messages domain'),
7373
new InputOption('only-missing', null, InputOption::VALUE_NONE, 'Display only missing messages'),
7474
new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Display only unused messages'),
7575
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),

src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ protected function configure(): void
7474
->setDefinition([
7575
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
7676
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
77-
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
77+
new InputOption('prefix', null, InputOption::VALUE_REQUIRED, 'Override the default prefix', '__'),
7878
new InputOption('no-fill', null, InputOption::VALUE_NONE, 'Extract translation keys without filling in values'),
79-
new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'xlf12'),
79+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Override the default output format', 'xlf12'),
8080
new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
8181
new InputOption('force', null, InputOption::VALUE_NONE, 'Should the extract be done'),
8282
new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
83-
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'Specify the domain to extract'),
83+
new InputOption('domain', null, InputOption::VALUE_REQUIRED, 'Specify the domain to extract'),
8484
new InputOption('sort', null, InputOption::VALUE_OPTIONAL, 'Return list of messages sorted alphabetically'),
85-
new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'),
85+
new InputOption('as-tree', null, InputOption::VALUE_REQUIRED, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'),
8686
])
8787
->setHelp(<<<'EOF'
8888
The <info>%command.name%</info> command extracts translation strings from templates

src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ public function process(ContainerBuilder $container): void
5555
continue;
5656
}
5757
$class = $adapter->getClass();
58+
$providers = $adapter->getArguments();
5859
while ($adapter instanceof ChildDefinition) {
5960
$adapter = $container->findDefinition($adapter->getParent());
6061
$class = $class ?: $adapter->getClass();
62+
$providers += $adapter->getArguments();
6163
if ($t = $adapter->getTag('cache.pool')) {
6264
$tags[0] += $t[0];
6365
}
@@ -87,7 +89,7 @@ public function process(ContainerBuilder $container): void
8789

8890
if (ChainAdapter::class === $class) {
8991
$adapters = [];
90-
foreach ($adapter->getArgument(0) as $provider => $adapter) {
92+
foreach ($providers['index_0'] ?? $providers[0] as $provider => $adapter) {
9193
if ($adapter instanceof ChildDefinition) {
9294
$chainedPool = $adapter;
9395
} else {

src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ public function testChainAdapterPool()
209209
$container->register('cache.adapter.apcu', ApcuAdapter::class)
210210
->setArguments([null, 0, null])
211211
->addTag('cache.pool');
212-
$container->register('cache.chain', ChainAdapter::class)
212+
$container->register('cache.adapter.chain', ChainAdapter::class);
213+
$container->setDefinition('cache.chain', new ChildDefinition('cache.adapter.chain'))
213214
->addArgument(['cache.adapter.array', 'cache.adapter.apcu'])
214215
->addTag('cache.pool');
215216
$container->setDefinition('cache.app', new ChildDefinition('cache.chain'))
@@ -224,7 +225,7 @@ public function testChainAdapterPool()
224225
$this->assertSame('cache.chain', $appCachePool->getParent());
225226

226227
$chainCachePool = $container->getDefinition('cache.chain');
227-
$this->assertNotInstanceOf(ChildDefinition::class, $chainCachePool);
228+
$this->assertInstanceOf(ChildDefinition::class, $chainCachePool);
228229
$this->assertCount(2, $chainCachePool->getArgument(0));
229230
$this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[0]);
230231
$this->assertSame('cache.adapter.array', $chainCachePool->getArgument(0)[0]->getParent());

src/Symfony/Component/Console/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,7 @@ private function splitStringByWidth(string $string, int $width): array
12771277

12781278
foreach (preg_split('//u', $m[0]) as $char) {
12791279
// test if $char could be appended to current line
1280-
if (mb_strwidth($line.$char, 'utf8') <= $width) {
1280+
if (Helper::width($line.$char) <= $width) {
12811281
$line .= $char;
12821282
continue;
12831283
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ public static function width(?string $string): int
4242
$string ??= '';
4343

4444
if (preg_match('//u', $string)) {
45-
return (new UnicodeString($string))->width(false);
45+
$string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count);
46+
47+
return (new UnicodeString($string))->width(false) + $count;
4648
}
4749

4850
if (false === $encoding = mb_detect_encoding($string, null, true)) {

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

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string
558558
}
559559

560560
// str_pad won't work properly with multi-byte strings, we need to fix the padding
561-
if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
562-
$width += \strlen($cell) - mb_strwidth($cell, $encoding);
563-
}
564-
561+
$width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0");
565562
$style = $this->getColumnStyle($column);
566563

567564
if ($cell instanceof TableSeparator) {
@@ -626,8 +623,48 @@ private function buildTableRows(array $rows): TableRows
626623
foreach ($rows[$rowKey] as $column => $cell) {
627624
$colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
628625

629-
if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) {
630-
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
626+
$minWrappedWidth = 0;
627+
$widthApplied = [];
628+
$lengthColumnBorder = $this->getColumnSeparatorWidth() + Helper::width($this->style->getCellRowContentFormat()) - 2;
629+
for ($i = $column; $i < ($column + $colspan); ++$i) {
630+
if (isset($this->columnMaxWidths[$i])) {
631+
$minWrappedWidth += $this->columnMaxWidths[$i];
632+
$widthApplied[] = ['type' => 'max', 'column' => $i];
633+
} elseif (($this->columnWidths[$i] ?? 0) > 0 && $colspan > 1) {
634+
$minWrappedWidth += $this->columnWidths[$i];
635+
$widthApplied[] = ['type' => 'min', 'column' => $i];
636+
}
637+
}
638+
if (1 === \count($widthApplied)) {
639+
if ($colspan > 1) {
640+
$minWrappedWidth *= $colspan; // previous logic
641+
}
642+
} elseif (\count($widthApplied) > 1) {
643+
$minWrappedWidth += (\count($widthApplied) - 1) * $lengthColumnBorder;
644+
}
645+
646+
$cellWidth = Helper::width(Helper::removeDecoration($formatter, $cell));
647+
if ($minWrappedWidth && $cellWidth > $minWrappedWidth) {
648+
$cell = $formatter->formatAndWrap($cell, $minWrappedWidth);
649+
}
650+
// update minimal columnWidths for spanned columns
651+
if ($colspan > 1 && $minWrappedWidth > 0) {
652+
$columnsMinWidthProcessed = [];
653+
$cellWidth = min($cellWidth, $minWrappedWidth);
654+
foreach ($widthApplied as $item) {
655+
if ('max' === $item['type'] && $cellWidth >= $this->columnMaxWidths[$item['column']]) {
656+
$minWidthColumn = $this->columnMaxWidths[$item['column']];
657+
$this->columnWidths[$item['column']] = $minWidthColumn;
658+
$columnsMinWidthProcessed[$item['column']] = true;
659+
$cellWidth -= $minWidthColumn + $lengthColumnBorder;
660+
}
661+
}
662+
for ($i = $column; $i < ($column + $colspan); ++$i) {
663+
if (isset($columnsMinWidthProcessed[$i])) {
664+
continue;
665+
}
666+
$this->columnWidths[$i] = $cellWidth + $lengthColumnBorder;
667+
}
631668
}
632669
if (!str_contains($cell ?? '', "\n")) {
633670
continue;

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

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,9 +1294,9 @@ public static function renderSetTitle()
12941294
'footer',
12951295
'default',
12961296
<<<'TABLE'
1297-
+---------------+---- Multiline
1297+
+---------------+--- Multiline
12981298
header
1299-
here -+------------------+
1299+
here +------------------+
13001300
| ISBN | Title | Author |
13011301
+---------------+--------------------------+------------------+
13021302
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
@@ -1576,17 +1576,17 @@ public function testWithColspanAndMaxWith()
15761576
$expected =
15771577
<<<TABLE
15781578
+-----------------+-----------------+-----------------+
1579-
| Lorem ipsum dolor sit amet, consectetur adipi |
1580-
| scing elit, sed do eiusmod tempor |
1579+
| Lorem ipsum dolor sit amet, consectetur adipiscing |
1580+
| elit, sed do eiusmod tempor |
15811581
+-----------------+-----------------+-----------------+
1582-
| Lorem ipsum dolor sit amet, consectetur |
1583-
| adipiscing elit, sed do eiusmod tempor |
1582+
| Lorem ipsum dolor sit amet, consectetur adipiscing |
1583+
| elit, sed do eiusmod tempor |
15841584
+-----------------+-----------------+-----------------+
1585-
| Lorem ipsum dolor sit amet, co | hello world |
1586-
| nsectetur | |
1585+
| Lorem ipsum dolor sit amet, conse | hello world |
1586+
| ctetur | |
15871587
+-----------------+-----------------+-----------------+
1588-
| hello world | Lorem ipsum dolor sit amet, co |
1589-
| | nsectetur adipiscing elit |
1588+
| hello world | Lorem ipsum dolor sit amet, conse |
1589+
| | ctetur adipiscing elit |
15901590
+-----------------+-----------------+-----------------+
15911591
| hello | world | Lorem ipsum |
15921592
| | | dolor sit amet, |
@@ -2078,4 +2078,36 @@ public function testGithubIssue52101HorizontalFalse()
20782078
$this->getOutputContent($output)
20792079
);
20802080
}
2081+
2082+
public function testGithubIssue60038WidthOfCellWithEmoji()
2083+
{
2084+
$table = (new Table($output = $this->getOutputStream()))
2085+
->setHeaderTitle('Test Title')
2086+
->setHeaders(['Title', 'Author'])
2087+
->setRows([
2088+
["🎭 💫 ☯"." Divine Comedy", "Dante Alighieri"],
2089+
// the snowflake (e2 9d 84 ef b8 8f) has a variant selector
2090+
["👑 ❄️ 🗡"." Game of Thrones", "George R.R. Martin"],
2091+
// the snowflake in text style (e2 9d 84 ef b8 8e) has a variant selector
2092+
["❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎", ""],
2093+
["And a very long line to show difference in previous lines", ""],
2094+
])
2095+
;
2096+
$table->render();
2097+
2098+
$this->assertSame(<<<TABLE
2099+
+---------------------------------- Test Title -------------+--------------------+
2100+
| Title | Author |
2101+
+-----------------------------------------------------------+--------------------+
2102+
| 🎭 💫 ☯ Divine Comedy | Dante Alighieri |
2103+
| 👑 ❄️ 🗡 Game of Thrones | George R.R. Martin |
2104+
| ❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎ | |
2105+
| And a very long line to show difference in previous lines | |
2106+
+-----------------------------------------------------------+--------------------+
2107+
2108+
TABLE
2109+
,
2110+
$this->getOutputContent($output)
2111+
);
2112+
}
20812113
}

src/Symfony/Component/Mailer/Command/MailerTestCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ protected function configure(): void
3535
{
3636
$this
3737
->addArgument('to', InputArgument::REQUIRED, 'The recipient of the message')
38-
->addOption('from', null, InputOption::VALUE_OPTIONAL, 'The sender of the message', '[email protected]')
39-
->addOption('subject', null, InputOption::VALUE_OPTIONAL, 'The subject of the message', 'Testing transport')
40-
->addOption('body', null, InputOption::VALUE_OPTIONAL, 'The body of the message', 'Testing body')
41-
->addOption('transport', null, InputOption::VALUE_OPTIONAL, 'The transport to be used')
38+
->addOption('from', null, InputOption::VALUE_REQUIRED, 'The sender of the message', '[email protected]')
39+
->addOption('subject', null, InputOption::VALUE_REQUIRED, 'The subject of the message', 'Testing transport')
40+
->addOption('body', null, InputOption::VALUE_REQUIRED, 'The body of the message', 'Testing body')
41+
->addOption('transport', null, InputOption::VALUE_REQUIRED, 'The transport to be used')
4242
->setHelp(<<<'EOF'
4343
The <info>%command.name%</info> command tests a Mailer transport by sending a simple email message:
4444

src/Symfony/Component/Messenger/Command/FailedMessagesRemoveCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ protected function configure(): void
3535
new InputArgument('id', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Specific message id(s) to remove'),
3636
new InputOption('all', null, InputOption::VALUE_NONE, 'Remove all failed messages from the transport'),
3737
new InputOption('force', null, InputOption::VALUE_NONE, 'Force the operation without confirmation'),
38-
new InputOption('transport', null, InputOption::VALUE_OPTIONAL, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION),
38+
new InputOption('transport', null, InputOption::VALUE_REQUIRED, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION),
3939
new InputOption('show-messages', null, InputOption::VALUE_NONE, 'Display messages before removing it (if multiple ids are given)'),
4040
])
4141
->setHelp(<<<'EOF'

0 commit comments

Comments
 (0)