@@ -47,6 +47,12 @@ class Html
4747
4848 protected static $ options ;
4949
50+ protected static $ rowIndex = 0 ;
51+
52+ protected static $ columnIndex = 0 ;
53+
54+ protected static $ rowSpanArray = [];
55+
5056 /**
5157 * @var Css
5258 */
@@ -424,6 +430,9 @@ protected static function parseTable($node, $element, &$styles)
424430 $ newElement ->getStyle ()->setStyleName ($ elementStyles ['className ' ]);
425431 }
426432
433+ self ::$ rowIndex = 0 ;
434+ self ::$ rowSpanArray = [];
435+
427436 $ attributes = $ node ->attributes ;
428437 if ($ attributes ->getNamedItem ('border ' )) {
429438 $ border = (int ) $ attributes ->getNamedItem ('border ' )->nodeValue ;
@@ -453,6 +462,9 @@ protected static function parseRow($node, $element, &$styles)
453462 $ height = $ rowStyles ['height ' ] ?? null ;
454463 unset($ rowStyles ['height ' ]); // would not apply
455464
465+ self ::$ columnIndex = 0 ;
466+ self ::$ rowIndex = self ::$ rowIndex + 1 ;
467+
456468 return $ element ->addRow ($ height , $ rowStyles );
457469 }
458470
@@ -468,22 +480,99 @@ protected static function parseRow($node, $element, &$styles)
468480 protected static function parseCell ($ node , $ element , &$ styles )
469481 {
470482 $ cellStyles = self ::recursiveParseStylesInHierarchy ($ node , $ styles ['cell ' ]);
483+ $ vMergeStyle = self ::recursiveParseStylesInHierarchy ($ node , $ styles ['cell ' ]);
484+ self ::$ columnIndex = self ::$ columnIndex + 1 ;
485+ $ search_row_items = ["rowIndex " => self ::$ rowIndex ];
486+ $ rowSpanCell = array_filter (self ::$ rowSpanArray , function ($ item ) use ($ search_row_items ) {
487+ return count (array_intersect_assoc ($ search_row_items , $ item )) == count ($ search_row_items );
488+ });
471489
472490 $ colspan = $ node ->getAttribute ('colspan ' );
473491 if (!empty ($ colspan )) {
474492 $ cellStyles ['gridSpan ' ] = $ colspan - 0 ;
493+ self ::$ columnIndex = self ::$ columnIndex + $ colspan - 1 ;
475494 }
476495
477- // set cell width to control column widths
478- $ width = $ cellStyles ['width ' ] ?? null ;
479- unset($ cellStyles ['width ' ]); // would not apply
480- $ cell = $ element ->addCell ($ width , $ cellStyles );
481-
482- if (self ::shouldAddTextRun ($ node )) {
483- return $ cell ->addTextRun (self ::filterOutNonInheritedStyles (self ::parseInlineStyle ($ node , $ styles ['paragraph ' ])));
484- }
485-
486- return $ cell ;
496+ $ rowspan = $ node ->getAttribute ('rowspan ' );
497+ if (!empty ($ rowspan )) {
498+ $ cellStyles ['vMerge ' ] = 'restart ' ;
499+ $ gridSpan = 0 ;
500+ $ colIndex = self ::$ columnIndex ;
501+ if (!empty ($ colspan )){
502+ $ gridSpan = $ colspan ;
503+ $ colIndex = self ::$ columnIndex - $ colspan + 1 ;
504+ }
505+ for ($ x = 1 ; $ x < $ rowspan ; $ x ++) {
506+ array_push (self ::$ rowSpanArray , ['columnIndex ' =>$ colIndex , 'rowIndex ' =>self ::$ rowIndex + $ x , 'colspan ' =>$ gridSpan ]);
507+ }
508+ }
509+
510+ $ search_column_item = ["columnIndex " => self ::$ columnIndex ];
511+ $ currentColumnRowSpan = array_filter ($ rowSpanCell , function ($ item ) use ($ search_column_item ) {
512+ return count (array_intersect_assoc ($ search_column_item , $ item )) == count ($ search_column_item );
513+ });
514+
515+ // set cell width to control column widths
516+ $ width = $ cellStyles ['width ' ] ?? null ;
517+ unset($ cellStyles ['width ' ]); // would not apply
518+ $ loop_check = self ::$ columnIndex ;
519+ if (count ($ currentColumnRowSpan ) == 0 ){
520+ $ cell = $ element ->addCell ($ width , $ cellStyles );
521+ $ loop_check = self ::$ columnIndex + 1 ;
522+ }
523+
524+ if (count ($ rowSpanCell ) > 0 ) {
525+ unset($ vMergeStyle ['width ' ]);
526+ foreach ($ rowSpanCell as $ row ) {
527+ if ($ row ['columnIndex ' ] == $ loop_check ){
528+ $ loop_check = $ row ['columnIndex ' ] + 1 ;
529+
530+ if ($ row ['colspan ' ] > 0 ) {
531+ $ vMergeStyle ['gridSpan ' ] = $ row ['colspan ' ];
532+ self ::$ columnIndex = self ::$ columnIndex + $ row ['colspan ' ] + 1 ;
533+ } else {
534+ unset($ vMergeStyle ['gridSpan ' ]);
535+ self ::$ columnIndex = self ::$ columnIndex + 1 ;
536+ }
537+ $ vMergeStyle ['vMerge ' ] = 'continue ' ;
538+ $ element ->addCell ($ width , $ vMergeStyle );
539+ }
540+ }
541+ }
542+
543+ if (count ($ currentColumnRowSpan ) > 0 ){
544+ $ cell = $ element ->addCell ($ width , $ cellStyles );
545+ }
546+
547+ $ search_item = ["columnIndex " => self ::$ columnIndex + 1 ];
548+ $ nextColumnRowSpan = array_filter ($ rowSpanCell , function ($ item ) use ($ search_item ) {
549+ return count (array_intersect_assoc ($ search_item , $ item )) == count ($ search_item );
550+ });
551+
552+ if (count ($ nextColumnRowSpan ) > 0 ) {
553+ unset($ vMergeStyle ['width ' ]);
554+ $ loop_check = self ::$ columnIndex + 1 ;
555+ foreach ($ rowSpanCell as $ row ) {
556+ if ($ row ['columnIndex ' ] == $ loop_check ){
557+ $ loop_check = $ row ['columnIndex ' ] + 1 ;
558+ if ($ row ['colspan ' ] > 0 ) {
559+ $ vMergeStyle ['gridSpan ' ] = $ row ['colspan ' ];
560+ self ::$ columnIndex = self ::$ columnIndex + $ row ['colspan ' ] + 1 ;
561+ } else {
562+ unset($ vMergeStyle ['gridSpan ' ]);
563+ self ::$ columnIndex = self ::$ columnIndex + 1 ;
564+ }
565+ $ vMergeStyle ['vMerge ' ] = 'continue ' ;
566+ $ element ->addCell ($ width , $ vMergeStyle );
567+ }
568+ }
569+ }
570+
571+ if (self ::shouldAddTextRun ($ node )) {
572+ return $ cell ->addTextRun (self ::filterOutNonInheritedStyles (self ::parseInlineStyle ($ node , $ styles ['paragraph ' ])));
573+ }
574+
575+ return $ cell ;
487576 }
488577
489578 /**
0 commit comments