2525use PhpOffice \PhpSpreadsheet \Shared \File ;
2626use PhpOffice \PhpSpreadsheet \Shared \StringHelper ;
2727use PhpOffice \PhpSpreadsheet \Spreadsheet ;
28+ use PhpOffice \PhpSpreadsheet \Style \Alignment ;
2829use PhpOffice \PhpSpreadsheet \Style \Fill ;
2930use PhpOffice \PhpSpreadsheet \Style \NumberFormat ;
31+ use PhpOffice \PhpSpreadsheet \Style \Protection ;
3032use PhpOffice \PhpSpreadsheet \Worksheet \Worksheet ;
3133use Throwable ;
3234use XMLReader ;
@@ -146,7 +148,14 @@ public function listWorksheetNames(string $filename): array
146148 /**
147149 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
148150 *
149- * @return array<int, array{worksheetName: string, lastColumnLetter: string, lastColumnIndex: int, totalRows: int, totalColumns: int, sheetState: string}>
151+ * @return array<int, array{
152+ * worksheetName: string,
153+ * lastColumnLetter: string,
154+ * lastColumnIndex: int,
155+ * totalRows: int,
156+ * totalColumns: int,
157+ * sheetState: string
158+ * }>
150159 */
151160 public function listWorksheetInfo (string $ filename ): array
152161 {
@@ -262,8 +271,21 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
262271 * fill?:array{
263272 * fillType?: string,
264273 * startColor?: array{rgb: string},
265- * }
266- * }> */
274+ * },
275+ * alignment?:array{
276+ * horizontal?: string,
277+ * readOrder?: int,
278+ * shrinkToFit?: bool,
279+ * textRotation?: int,
280+ * vertical?: string,
281+ * wrapText?: bool,
282+ * },
283+ * protection?:array{
284+ * locked?: string,
285+ * hidden?: string,
286+ * },
287+ * }>
288+ */
267289 private array $ allStyles ;
268290
269291 /**
@@ -309,6 +331,7 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp
309331 foreach ($ automaticStyles as $ automaticStyle ) {
310332 $ styleFamily = $ automaticStyle ->getAttributeNS ($ styleNs , 'family ' );
311333 if ($ styleFamily === 'table-cell ' ) {
334+ $ fonts = [];
312335 foreach ($ automaticStyle ->getElementsByTagNameNS ($ styleNs , 'text-properties ' ) as $ textProperty ) {
313336 $ fonts = $ this ->getFontStyles ($ textProperty , $ styleNs , $ fontNs );
314337 }
@@ -330,22 +353,24 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp
330353 $ fonts = $ this ->getFontStyles ($ textProperty , $ styleNs , $ fontNs );
331354 }
332355 foreach ($ automaticStyle ->getElementsByTagNameNS ($ styleNs , 'table-cell-properties ' ) as $ tableCellProperty ) {
333- $ fills = $ this ->getFillStyles ($ tableCellProperty , $ styleNs , $ fontNs );
356+ $ fills = $ this ->getFillStyles ($ tableCellProperty , $ fontNs );
334357 }
335358 if ($ styleName !== '' ) {
336- $ allStyles = [];
337359 if (!empty ($ fonts )) {
338360 $ this ->allStyles [$ styleName ]['font ' ] = $ fonts ;
339- $ allStyles ['font ' ] = $ fonts ;
361+ if (!$ defaultStyleSet && $ styleName === 'Default ' ) {
362+ $ spreadsheet ->getDefaultStyle ()
363+ ->getFont ()
364+ ->applyFromArray ($ fonts );
365+ }
340366 }
341367 if (!empty ($ fills )) {
342368 $ this ->allStyles [$ styleName ]['fill ' ] = $ fills ;
343- $ allStyles ['fill ' ] = $ fills ;
344- }
345- if (!$ defaultStyleSet && $ styleName === 'Default ' && isset ($ allStyles ['font ' ])) {
346- $ spreadsheet ->getDefaultStyle ()
347- ->getFont ()
348- ->applyFromArray ($ allStyles ['font ' ]);
369+ if ($ styleName === 'Default ' ) {
370+ $ spreadsheet ->getDefaultStyle ()
371+ ->getFill ()
372+ ->applyFromArray ($ fills );
373+ }
349374 }
350375 }
351376 }
@@ -384,12 +409,19 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp
384409 }
385410 }
386411 if ($ styleFamily === 'table-cell ' ) {
387- $ fonts = $ fills = [];
412+ $ fonts = $ fills = $ alignment1 = $ alignment2 = $ protection = [];
388413 foreach ($ automaticStyle ->getElementsByTagNameNS ($ styleNs , 'text-properties ' ) as $ textProperty ) {
389414 $ fonts = $ this ->getFontStyles ($ textProperty , $ styleNs , $ fontNs );
390415 }
391416 foreach ($ automaticStyle ->getElementsByTagNameNS ($ styleNs , 'table-cell-properties ' ) as $ tableCellProperty ) {
392- $ fills = $ this ->getFillStyles ($ tableCellProperty , $ styleNs , $ fontNs );
417+ $ fills = $ this ->getFillStyles ($ tableCellProperty , $ fontNs );
418+ $ protection = $ this ->getProtectionStyles ($ tableCellProperty , $ styleNs );
419+ }
420+ foreach ($ automaticStyle ->getElementsByTagNameNS ($ styleNs , 'table-cell-properties ' ) as $ tableCellProperty ) {
421+ $ alignment1 = $ this ->getAlignment1Styles ($ tableCellProperty , $ styleNs , $ fontNs );
422+ }
423+ foreach ($ automaticStyle ->getElementsByTagNameNS ($ styleNs , 'paragraph-properties ' ) as $ paragraphProperty ) {
424+ $ alignment2 = $ this ->getAlignment2Styles ($ paragraphProperty , $ styleNs , $ fontNs );
393425 }
394426 if ($ styleName !== '' ) {
395427 if (!empty ($ fonts )) {
@@ -398,6 +430,13 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp
398430 if (!empty ($ fills )) {
399431 $ this ->allStyles [$ styleName ]['fill ' ] = $ fills ;
400432 }
433+ $ alignment = array_merge ($ alignment1 , $ alignment2 );
434+ if (!empty ($ alignment )) {
435+ $ this ->allStyles [$ styleName ]['alignment ' ] = $ alignment ;
436+ }
437+ if (!empty ($ protection )) {
438+ $ this ->allStyles [$ styleName ]['protection ' ] = $ protection ;
439+ }
401440 }
402441 }
403442 }
@@ -1340,15 +1379,133 @@ protected function getFontStyles(DOMElement $textProperty, string $styleNs, stri
13401379 * startColor?: array{rgb: string},
13411380 * }
13421381 */
1343- protected function getFillStyles (DOMElement $ tableCellProperties , string $ styleNs , string $ fontNs ): array
1382+ protected function getFillStyles (DOMElement $ tableCellProperties , string $ fontNs ): array
13441383 {
13451384 $ fills = [];
13461385 $ temp = $ tableCellProperties ->getAttributeNs ($ fontNs , 'background-color ' );
13471386 if (Preg::isMatch ('/^#[a-f0-9]{6}$/i ' , $ temp )) {
13481387 $ fills ['fillType ' ] = Fill::FILL_SOLID ;
13491388 $ fills ['startColor ' ] = ['rgb ' => substr ($ temp , 1 )];
1389+ } elseif ($ temp === 'transparent ' ) {
1390+ $ fills ['fillType ' ] = Fill::FILL_NONE ;
13501391 }
13511392
13521393 return $ fills ;
13531394 }
1395+
1396+ private const MAP_VERTICAL = [
1397+ 'top ' => Alignment::VERTICAL_TOP ,
1398+ 'middle ' => Alignment::VERTICAL_CENTER ,
1399+ 'automatic ' => Alignment::VERTICAL_JUSTIFY ,
1400+ 'bottom ' => Alignment::VERTICAL_BOTTOM ,
1401+ ];
1402+ private const MAP_HORIZONTAL = [
1403+ 'center ' => Alignment::HORIZONTAL_CENTER ,
1404+ 'end ' => Alignment::HORIZONTAL_RIGHT ,
1405+ 'justify ' => Alignment::HORIZONTAL_FILL ,
1406+ 'start ' => Alignment::HORIZONTAL_LEFT ,
1407+ ];
1408+
1409+ /** @return array{
1410+ * shrinkToFit?: bool,
1411+ * textRotation?: int,
1412+ * vertical?: string,
1413+ * wrapText?: bool,
1414+ * }
1415+ */
1416+ protected function getAlignment1Styles (DOMElement $ tableCellProperties , string $ styleNs , string $ fontNs ): array
1417+ {
1418+ $ alignment1 = [];
1419+ $ temp = $ tableCellProperties ->getAttributeNs ($ styleNs , 'rotation-angle ' );
1420+ if (is_numeric ($ temp )) {
1421+ $ temp2 = (int ) $ temp ;
1422+ if ($ temp2 > 90 ) {
1423+ $ temp2 -= 360 ;
1424+ }
1425+ if ($ temp2 >= -90 && $ temp2 <= 90 ) {
1426+ $ alignment1 ['textRotation ' ] = (int ) $ temp2 ;
1427+ }
1428+ }
1429+ $ temp = $ tableCellProperties ->getAttributeNs ($ styleNs , 'vertical-align ' );
1430+ $ temp2 = self ::MAP_VERTICAL [$ temp ] ?? '' ;
1431+ if ($ temp2 !== '' ) {
1432+ $ alignment1 ['vertical ' ] = $ temp2 ;
1433+ }
1434+ $ temp = $ tableCellProperties ->getAttributeNs ($ fontNs , 'wrap-option ' );
1435+ if ($ temp === 'wrap ' ) {
1436+ $ alignment1 ['wrapText ' ] = true ;
1437+ } elseif ($ temp === 'no-wrap ' ) {
1438+ $ alignment1 ['wrapText ' ] = false ;
1439+ }
1440+ $ temp = $ tableCellProperties ->getAttributeNs ($ styleNs , 'shrink-to-fit ' );
1441+ if ($ temp === 'true ' || $ temp === 'false ' ) {
1442+ $ alignment1 ['shrinkToFit ' ] = $ temp === 'true ' ;
1443+ }
1444+
1445+ return $ alignment1 ;
1446+ }
1447+
1448+ /** @return array{
1449+ * horizontal?: string,
1450+ * readOrder?: int,
1451+ * }
1452+ */
1453+ protected function getAlignment2Styles (DOMElement $ paragraphProperties , string $ styleNs , string $ fontNs ): array
1454+ {
1455+ $ alignment2 = [];
1456+ $ temp = $ paragraphProperties ->getAttributeNs ($ fontNs , 'text-align ' );
1457+ $ temp2 = self ::MAP_HORIZONTAL [$ temp ] ?? '' ;
1458+ if ($ temp2 !== '' ) {
1459+ $ alignment2 ['horizontal ' ] = $ temp2 ;
1460+ }
1461+ $ temp = $ paragraphProperties ->getAttributeNs ($ fontNs , 'margin-left ' ) ?: $ paragraphProperties ->getAttributeNs ($ fontNs , 'margin-right ' );
1462+ if (Preg::isMatch ('/^\d+([.]\d+)?(cm|in|mm|pt)$/ ' , $ temp )) {
1463+ $ dimension = new HelperDimension ($ temp );
1464+ $ alignment2 ['indent ' ] = (int ) round ($ dimension ->toUnit ('px ' ) / Alignment::INDENT_UNITS_TO_PIXELS );
1465+ }
1466+
1467+ $ temp = $ paragraphProperties ->getAttributeNs ($ styleNs , 'writing-mode ' );
1468+ if ($ temp === 'rl-tb ' ) {
1469+ $ alignment2 ['readOrder ' ] = Alignment::READORDER_RTL ;
1470+ } elseif ($ temp === 'lr-tb ' ) {
1471+ $ alignment2 ['readOrder ' ] = Alignment::READORDER_LTR ;
1472+ }
1473+
1474+ return $ alignment2 ;
1475+ }
1476+
1477+ /** @return array{
1478+ * locked?: string,
1479+ * hidden?: string,
1480+ * }
1481+ */
1482+ protected function getProtectionStyles (DOMElement $ tableCellProperties , string $ styleNs ): array
1483+ {
1484+ $ protection = [];
1485+ $ temp = $ tableCellProperties ->getAttributeNs ($ styleNs , 'cell-protect ' );
1486+ switch ($ temp ) {
1487+ case 'protected formula-hidden ' :
1488+ $ protection ['locked ' ] = Protection::PROTECTION_PROTECTED ;
1489+ $ protection ['hidden ' ] = Protection::PROTECTION_PROTECTED ;
1490+
1491+ break ;
1492+ case 'formula-hidden ' :
1493+ $ protection ['locked ' ] = Protection::PROTECTION_UNPROTECTED ;
1494+ $ protection ['hidden ' ] = Protection::PROTECTION_PROTECTED ;
1495+
1496+ break ;
1497+ case 'protected ' :
1498+ $ protection ['locked ' ] = Protection::PROTECTION_PROTECTED ;
1499+ $ protection ['hidden ' ] = Protection::PROTECTION_UNPROTECTED ;
1500+
1501+ break ;
1502+ case 'none ' :
1503+ $ protection ['locked ' ] = Protection::PROTECTION_UNPROTECTED ;
1504+ $ protection ['hidden ' ] = Protection::PROTECTION_UNPROTECTED ;
1505+
1506+ break ;
1507+ }
1508+
1509+ return $ protection ;
1510+ }
13541511}
0 commit comments