2828class Table
2929{
3030 private const SEPARATOR_TOP = 0 ;
31- private const SEPARATOR_MID = 1 ;
32- private const SEPARATOR_BOTTOM = 2 ;
31+ private const SEPARATOR_TOP_BOTTOM = 1 ;
32+ private const SEPARATOR_MID = 2 ;
33+ private const SEPARATOR_BOTTOM = 3 ;
34+ private const BORDER_OUTSIDE = 0 ;
35+ private const BORDER_INSIDE = 1 ;
3336
3437 /**
3538 * Table headers.
@@ -328,7 +331,7 @@ public function render()
328331 }
329332
330333 if ($ isHeader || $ isFirstRow ) {
331- $ this ->renderRowSeparator ($ isFirstRow ? self ::SEPARATOR_MID : self ::SEPARATOR_TOP );
334+ $ this ->renderRowSeparator ($ isFirstRow ? self ::SEPARATOR_TOP_BOTTOM : self ::SEPARATOR_TOP );
332335 if ($ isFirstRow ) {
333336 $ isFirstRow = false ;
334337 }
@@ -353,22 +356,25 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID)
353356 return ;
354357 }
355358
356- if (!$ this ->style ->getHorizontalBorderChar () && !$ this ->style ->getCrossingChar ()) {
359+ $ borders = $ this ->style ->getBorderChars ();
360+ if (!$ borders [0 ] && !$ borders [2 ] && !$ this ->style ->getCrossingChar ()) {
357361 return ;
358362 }
359363
360- $ chars = $ this ->style ->getCrossingChars ();
364+ $ crossings = $ this ->style ->getCrossingChars ();
361365 if (self ::SEPARATOR_MID === $ type ) {
362- list ($ leftChar , $ midChar , $ rightChar ) = array ($ chars [ 8 ], $ chars [0 ], $ chars [4 ]);
366+ list ($ horizontal , $ leftChar , $ midChar , $ rightChar ) = array ($ borders [ 2 ], $ crossings [ 8 ], $ crossings [0 ], $ crossings [4 ]);
363367 } elseif (self ::SEPARATOR_TOP === $ type ) {
364- list ($ leftChar , $ midChar , $ rightChar ) = array ($ chars [1 ], $ chars [2 ], $ chars [3 ]);
368+ list ($ horizontal , $ leftChar , $ midChar , $ rightChar ) = array ($ borders [0 ], $ crossings [1 ], $ crossings [2 ], $ crossings [3 ]);
369+ } elseif (self ::SEPARATOR_TOP_BOTTOM === $ type ) {
370+ list ($ horizontal , $ leftChar , $ midChar , $ rightChar ) = array ($ borders [0 ], $ crossings [9 ], $ crossings [10 ], $ crossings [11 ]);
365371 } else {
366- list ($ leftChar , $ midChar , $ rightChar ) = array ($ chars [ 7 ], $ chars [6 ], $ chars [5 ]);
372+ list ($ horizontal , $ leftChar , $ midChar , $ rightChar ) = array ($ borders [ 0 ], $ crossings [ 7 ], $ crossings [6 ], $ crossings [5 ]);
367373 }
368374
369375 $ markup = $ leftChar ;
370376 for ($ column = 0 ; $ column < $ count ; ++$ column ) {
371- $ markup .= str_repeat ($ this -> style -> getHorizontalBorderChar () , $ this ->effectiveColumnWidths [$ column ]);
377+ $ markup .= str_repeat ($ horizontal , $ this ->effectiveColumnWidths [$ column ]);
372378 $ markup .= $ column === $ count - 1 ? $ rightChar : $ midChar ;
373379 }
374380
@@ -378,9 +384,11 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID)
378384 /**
379385 * Renders vertical column separator.
380386 */
381- private function renderColumnSeparator ()
387+ private function renderColumnSeparator ($ type = self :: BORDER_OUTSIDE )
382388 {
383- return sprintf ($ this ->style ->getBorderFormat (), $ this ->style ->getVerticalBorderChar ());
389+ $ borders = $ this ->style ->getBorderChars ();
390+
391+ return sprintf ($ this ->style ->getBorderFormat (), self ::BORDER_OUTSIDE === $ type ? $ borders [1 ] : $ borders [3 ]);
384392 }
385393
386394 /**
@@ -390,10 +398,12 @@ private function renderColumnSeparator()
390398 */
391399 private function renderRow (array $ row , string $ cellFormat )
392400 {
393- $ rowContent = $ this ->renderColumnSeparator ();
394- foreach ($ this ->getRowColumns ($ row ) as $ column ) {
401+ $ rowContent = $ this ->renderColumnSeparator (self ::BORDER_OUTSIDE );
402+ $ columns = $ this ->getRowColumns ($ row );
403+ $ last = count ($ columns ) - 1 ;
404+ foreach ($ columns as $ i => $ column ) {
395405 $ rowContent .= $ this ->renderCell ($ row , $ column , $ cellFormat );
396- $ rowContent .= $ this ->renderColumnSeparator ();
406+ $ rowContent .= $ this ->renderColumnSeparator ($ last === $ i ? self :: BORDER_OUTSIDE : self :: BORDER_INSIDE );
397407 }
398408 $ this ->output ->writeln ($ rowContent );
399409 }
@@ -420,7 +430,7 @@ private function renderCell(array $row, int $column, string $cellFormat)
420430 $ style = $ this ->getColumnStyle ($ column );
421431
422432 if ($ cell instanceof TableSeparator) {
423- return sprintf ($ style ->getBorderFormat (), str_repeat ($ style ->getHorizontalBorderChar () , $ width ));
433+ return sprintf ($ style ->getBorderFormat (), str_repeat ($ style ->getBorderChars ()[ 2 ] , $ width ));
424434 }
425435
426436 $ width += Helper::strlen ($ cell ) - Helper::strlenWithoutDecoration ($ this ->output ->getFormatter (), $ cell );
@@ -648,7 +658,7 @@ private function calculateColumnsWidth(iterable $rows)
648658
649659 private function getColumnSeparatorWidth (): int
650660 {
651- return strlen (sprintf ($ this ->style ->getBorderFormat (), $ this ->style ->getVerticalBorderChar () ));
661+ return strlen (sprintf ($ this ->style ->getBorderFormat (), $ this ->style ->getBorderChars ()[ 3 ] ));
652662 }
653663
654664 private function getCellWidth (array $ row , int $ column ): int
@@ -678,39 +688,46 @@ private static function initStyles()
678688 {
679689 $ borderless = new TableStyle ();
680690 $ borderless
681- ->setHorizontalBorderChar ('= ' )
682- ->setVerticalBorderChar (' ' )
691+ ->setHorizontalBorderChars ('= ' )
692+ ->setVerticalBorderChars (' ' )
683693 ->setDefaultCrossingChar (' ' )
684694 ;
685695
686696 $ compact = new TableStyle ();
687697 $ compact
688- ->setHorizontalBorderChar ('' )
689- ->setVerticalBorderChar (' ' )
698+ ->setHorizontalBorderChars ('' )
699+ ->setVerticalBorderChars (' ' )
690700 ->setDefaultCrossingChar ('' )
691701 ->setCellRowContentFormat ('%s ' )
692702 ;
693703
694704 $ styleGuide = new TableStyle ();
695705 $ styleGuide
696- ->setHorizontalBorderChar ('- ' )
697- ->setVerticalBorderChar (' ' )
706+ ->setHorizontalBorderChars ('- ' )
707+ ->setVerticalBorderChars (' ' )
698708 ->setDefaultCrossingChar (' ' )
699709 ->setCellHeaderFormat ('%s ' )
700710 ;
701711
702712 $ box = (new TableStyle ())
703- ->setHorizontalBorderChar ('─ ' )
704- ->setVerticalBorderChar ('│ ' )
713+ ->setHorizontalBorderChars ('─ ' )
714+ ->setVerticalBorderChars ('│ ' )
705715 ->setCrossingChars ('┼ ' , '┌ ' , '┬ ' , '┐ ' , '┤ ' , '┘ ' , '┴ ' , '└ ' , '├ ' )
706716 ;
707717
718+ $ boxDouble = (new TableStyle ())
719+ ->setHorizontalBorderChars ('═ ' , '─ ' )
720+ ->setVerticalBorderChars ('║ ' , '│ ' )
721+ ->setCrossingChars ('┼ ' , '╔ ' , '╤ ' , '╗ ' , '╢ ' , '╝ ' , '╧ ' , '╚ ' , '╟ ' , '╠ ' , '╪ ' , '╣ ' )
722+ ;
723+
708724 return array (
709725 'default ' => new TableStyle (),
710726 'borderless ' => $ borderless ,
711727 'compact ' => $ compact ,
712728 'symfony-style-guide ' => $ styleGuide ,
713729 'box ' => $ box ,
730+ 'box-double ' => $ boxDouble ,
714731 );
715732 }
716733
0 commit comments