Skip to content

Commit f74236b

Browse files
dimtrovichadhocore
authored andcommitted
patch: add support for dynamically defining the style of a cell via a callable
1 parent 4ed7e63 commit f74236b

File tree

2 files changed

+180
-6
lines changed

2 files changed

+180
-6
lines changed

src/Output/Table.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,14 @@ public function render(array $rows, array $styles = []): string
7272
$style = $styles['*:' . $colNumber] ?? $styles[$col];
7373
} else if (isset($styles[$line . ':*'])) { // row, 2:*
7474
$style = $styles[$line . ':*'];
75+
} else if (isset($styles['*:*'])) { // any cell, *:*
76+
$style = $styles['*:*'];
7577
} else {
7678
$style = $styles[['even', 'odd'][(int) $odd]];
7779
}
7880

79-
[$start, $end] = $style;
80-
81-
$text = $row[$col] ?? '';
81+
$text = $row[$col] ?? '';
82+
[$start, $end] = $this->parseStyle($style, $text, $row, $rows);
8283

8384
if (preg_match('/(\\x1b(?:.+)m)/U', $text, $matches)) {
8485
$word = str_replace($matches[1], '', $text);
@@ -150,12 +151,30 @@ protected function normalizeStyles(array $styles): array
150151

151152
foreach ($styles as $for => $style) {
152153
if (is_string($style) && $style !== '') {
153-
$style = ['<' . trim($style, '<> ') . '>', '</end>'];
154+
$default[$for] = ['<' . trim($style, '<> ') . '>', '</end>'];
155+
} else if (str_contains($for, ':') && is_callable($style)) {
156+
$default[$for] = $style;
154157
}
155-
156-
$default[$for] = $style;
157158
}
158159

159160
return $default;
160161
}
162+
163+
protected function parseStyle(array|callable $style, $val, array $row, array $table): array
164+
{
165+
if (is_array($style)) {
166+
return $style;
167+
}
168+
169+
$style = call_user_func($style, $val, $row, $table);
170+
171+
if (is_string($style) && $style !== '') {
172+
return ['<' . trim($style, '<> ') . '>', '</end>'];
173+
}
174+
if (is_array($style) && count($style) === 2) {
175+
return $style;
176+
}
177+
178+
return ['', ''];
179+
}
161180
}

tests/Output/TableTest.php

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,107 @@ public function test_render_with_row_specific_styles(): void
363363
$this->assertSame($expectedOutput, trim($result));
364364
}
365365

366+
public function test_render_with_callable_styles(): void
367+
{
368+
$rows = [
369+
['name' => 'John Doe', 'age' => '30'],
370+
['name' => 'Jane Smith', 'age' => '25'],
371+
];
372+
373+
$styles = [
374+
'head' => 'boldGreen',
375+
'1:1' => function ($val, $row, $table) {
376+
return $val === 'John Doe' ? 'boldRed' : '';
377+
},
378+
'2:2' => function ($val, $row, $table) {
379+
return $val === '25' ? 'boldBlue' : '';
380+
},
381+
];
382+
383+
$expectedOutput =
384+
"+------------+-----+" . PHP_EOL .
385+
"|<boldGreen> Name </end>|<boldGreen> Age </end>|" . PHP_EOL .
386+
"+------------+-----+" . PHP_EOL .
387+
"|<boldRed> John Doe </end>| 30 |" . PHP_EOL .
388+
"| Jane Smith |<boldBlue> 25 </end>|" . PHP_EOL .
389+
"+------------+-----+";
390+
391+
$result = $this->table->render($rows, $styles);
392+
393+
$this->assertSame($expectedOutput, trim($result));
394+
}
395+
396+
public function test_render_with_callable_styles_using_row(): void
397+
{
398+
$rows = [
399+
['name' => 'John Doe', 'age' => '30'],
400+
['name' => 'Jane Smith', 'age' => '25'],
401+
['name' => 'Bob Johnson', 'age' => '40'],
402+
];
403+
404+
$styles = [
405+
'head' => 'boldGreen',
406+
'*:2' => function ($val, $row) {
407+
if ($val == 25) {
408+
return 'boldYellow';
409+
}
410+
411+
return $row['age'] >= 30 ? 'boldRed' : '';
412+
},
413+
];
414+
415+
$expectedOutput =
416+
"+-------------+-----+" . PHP_EOL .
417+
"|<boldGreen> Name </end>|<boldGreen> Age </end>|" . PHP_EOL .
418+
"+-------------+-----+" . PHP_EOL .
419+
"| John Doe |<boldRed> 30 </end>|" . PHP_EOL .
420+
"| Jane Smith |<boldYellow> 25 </end>|" . PHP_EOL .
421+
"| Bob Johnson |<boldRed> 40 </end>|" . PHP_EOL .
422+
"+-------------+-----+";
423+
424+
$result = $this->table->render($rows, $styles);
425+
426+
$this->assertSame($expectedOutput, trim($result));
427+
}
428+
429+
public function test_render_with_callable_styles_on_any_cell(): void
430+
{
431+
$rows = [
432+
['name' => 'John Doe', 'age' => '30'],
433+
['name' => 'Jane Smith', 'age' => '25'],
434+
['name' => 'Alice Bob', 'age' => '10'],
435+
['name' => 'Bob Johnson', 'age' => '40'],
436+
['name' => 'Jane X', 'age' => '50'],
437+
];
438+
439+
$styles = [
440+
'head' => 'boldGreen',
441+
'*:*' => function ($val, $row) {
442+
if ($val === 'Jane X') {
443+
return 'yellow';
444+
}
445+
if ($val == 10) {
446+
return 'purple';
447+
}
448+
return $row['age'] >= 30 ? 'boldRed' : '';
449+
},
450+
];
451+
452+
$expectedOutput =
453+
"+-------------+-----+" . PHP_EOL .
454+
"|<boldGreen> Name </end>|<boldGreen> Age </end>|" . PHP_EOL .
455+
"+-------------+-----+" . PHP_EOL .
456+
"|<boldRed> John Doe </end>|<boldRed> 30 </end>|" . PHP_EOL .
457+
"| Jane Smith | 25 |" . PHP_EOL .
458+
"| Alice Bob |<purple> 10 </end>|" . PHP_EOL .
459+
"|<boldRed> Bob Johnson </end>|<boldRed> 40 </end>|" . PHP_EOL .
460+
"|<yellow> Jane X </end>|<boldRed> 50 </end>|" . PHP_EOL .
461+
"+-------------+-----+";
462+
463+
$result = $this->table->render($rows, $styles);
464+
465+
$this->assertSame($expectedOutput, trim($result));
466+
}
366467
public function test_render_with_mixed_specific_styles(): void
367468
{
368469
$rows = [
@@ -392,6 +493,35 @@ public function test_render_with_mixed_specific_styles(): void
392493
$this->assertSame($expectedOutput, trim($result));
393494
}
394495

496+
public function test_render_with_styles_using_column_name(): void
497+
{
498+
$rows = [
499+
['name' => 'John Doe', 'age' => '30', 'city' => 'New York'],
500+
['name' => 'Jane Smith', 'age' => '25', 'city' => 'Los Angeles'],
501+
['name' => 'Bob Johnson', 'age' => '40', 'city' => 'Chicago'],
502+
];
503+
504+
$styles = [
505+
'head' => 'boldGreen',
506+
'1:2' => 'boldRed', // Cell-specific style for first row, second column
507+
'city' => 'boldBlue',
508+
'name' => 'italic',
509+
];
510+
511+
$expectedOutput =
512+
"+-------------+-----+-------------+" . PHP_EOL .
513+
"|<boldGreen> Name </end>|<boldGreen> Age </end>|<boldGreen> City </end>|" . PHP_EOL .
514+
"+-------------+-----+-------------+" . PHP_EOL .
515+
"|<italic> John Doe </end>|<boldRed> 30 </end>|<boldBlue> New York </end>|" . PHP_EOL .
516+
"|<italic> Jane Smith </end>| 25 |<boldBlue> Los Angeles </end>|" . PHP_EOL .
517+
"|<italic> Bob Johnson </end>| 40 |<boldBlue> Chicago </end>|" . PHP_EOL .
518+
"+-------------+-----+-------------+";
519+
520+
$result = $this->table->render($rows, $styles);
521+
522+
$this->assertSame($expectedOutput, trim($result));
523+
}
524+
395525
public function test_render_with_empty_styles_array(): void
396526
{
397527
$rows = [
@@ -411,6 +541,31 @@ public function test_render_with_empty_styles_array(): void
411541

412542
$this->assertSame($expectedOutput, trim($result));
413543
}
544+
545+
public function test_render_handles_invalid_style_keys_gracefully(): void
546+
{
547+
$rows = [
548+
['name' => 'John Doe', 'age' => '30'],
549+
['name' => 'Jane Smith', 'age' => '25'],
550+
];
551+
552+
$invalidStyles = [
553+
'invalidKey' => 'boldRed', // Invalid style key
554+
'head' => 'boldGreen',
555+
];
556+
557+
$expectedOutput =
558+
"+------------+-----+" . PHP_EOL .
559+
"|<boldGreen> Name </end>|<boldGreen> Age </end>|" . PHP_EOL .
560+
"+------------+-----+" . PHP_EOL .
561+
"| John Doe | 30 |" . PHP_EOL .
562+
"| Jane Smith | 25 |" . PHP_EOL .
563+
"+------------+-----+";
564+
565+
$result = $this->table->render($rows, $invalidStyles);
566+
567+
$this->assertSame($expectedOutput, trim($result));
568+
}
414569
public function test_render_with_large_number_of_columns(): void
415570
{
416571
$columns = 100;

0 commit comments

Comments
 (0)