See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; 4 5 use PhpOffice\PhpSpreadsheet\Cell\Coordinate; 6 use PhpOffice\PhpSpreadsheet\Reader\DefaultReadFilter; 7 use PhpOffice\PhpSpreadsheet\Reader\IReadFilter; 8 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; 9 use SimpleXMLElement; 10 11 class ColumnAndRowAttributes extends BaseParserClass 12 { 13 /** @var Worksheet */ 14 private $worksheet; 15 16 /** @var ?SimpleXMLElement */ 17 private $worksheetXml; 18 19 public function __construct(Worksheet $workSheet, ?SimpleXMLElement $worksheetXml = null) 20 { 21 $this->worksheet = $workSheet; 22 $this->worksheetXml = $worksheetXml; 23 } 24 25 /** 26 * Set Worksheet column attributes by attributes array passed. 27 * 28 * @param string $columnAddress A, B, ... DX, ... 29 * @param array $columnAttributes array of attributes (indexes are attribute name, values are value) 30 * 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ? 31 */ 32 private function setColumnAttributes($columnAddress, array $columnAttributes): void 33 { 34 if (isset($columnAttributes['xfIndex'])) { 35 $this->worksheet->getColumnDimension($columnAddress)->setXfIndex($columnAttributes['xfIndex']); 36 } 37 if (isset($columnAttributes['visible'])) { 38 $this->worksheet->getColumnDimension($columnAddress)->setVisible($columnAttributes['visible']); 39 } 40 if (isset($columnAttributes['collapsed'])) { 41 $this->worksheet->getColumnDimension($columnAddress)->setCollapsed($columnAttributes['collapsed']); 42 } 43 if (isset($columnAttributes['outlineLevel'])) { 44 $this->worksheet->getColumnDimension($columnAddress)->setOutlineLevel($columnAttributes['outlineLevel']); 45 } 46 if (isset($columnAttributes['width'])) { 47 $this->worksheet->getColumnDimension($columnAddress)->setWidth($columnAttributes['width']); 48 } 49 } 50 51 /** 52 * Set Worksheet row attributes by attributes array passed. 53 * 54 * @param int $rowNumber 1, 2, 3, ... 99, ... 55 * @param array $rowAttributes array of attributes (indexes are attribute name, values are value) 56 * 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ? 57 */ 58 private function setRowAttributes($rowNumber, array $rowAttributes): void 59 { 60 if (isset($rowAttributes['xfIndex'])) { 61 $this->worksheet->getRowDimension($rowNumber)->setXfIndex($rowAttributes['xfIndex']); 62 } 63 if (isset($rowAttributes['visible'])) { 64 $this->worksheet->getRowDimension($rowNumber)->setVisible($rowAttributes['visible']); 65 } 66 if (isset($rowAttributes['collapsed'])) { 67 $this->worksheet->getRowDimension($rowNumber)->setCollapsed($rowAttributes['collapsed']); 68 } 69 if (isset($rowAttributes['outlineLevel'])) { 70 $this->worksheet->getRowDimension($rowNumber)->setOutlineLevel($rowAttributes['outlineLevel']); 71 } 72 if (isset($rowAttributes['rowHeight'])) { 73 $this->worksheet->getRowDimension($rowNumber)->setRowHeight($rowAttributes['rowHeight']); 74 } 75 } 76 77 public function load(?IReadFilter $readFilter = null, bool $readDataOnly = false): void 78 { 79 if ($this->worksheetXml === null) { 80 return; 81 } 82 83 $columnsAttributes = []; 84 $rowsAttributes = []; 85 if (isset($this->worksheetXml->cols)) { 86 $columnsAttributes = $this->readColumnAttributes($this->worksheetXml->cols, $readDataOnly); 87 } 88 89 if ($this->worksheetXml->sheetData && $this->worksheetXml->sheetData->row) { 90 $rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly); 91 } 92 93 if ($readFilter !== null && get_class($readFilter) === DefaultReadFilter::class) { 94 $readFilter = null; 95 } 96 97 // set columns/rows attributes 98 $columnsAttributesAreSet = []; 99 foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) { 100 if ( 101 $readFilter === null || 102 !$this->isFilteredColumn($readFilter, $columnCoordinate, $rowsAttributes) 103 ) { 104 if (!isset($columnsAttributesAreSet[$columnCoordinate])) { 105 $this->setColumnAttributes($columnCoordinate, $columnAttributes); 106 $columnsAttributesAreSet[$columnCoordinate] = true; 107 } 108 } 109 } 110 111 $rowsAttributesAreSet = []; 112 foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) { 113 if ( 114 $readFilter === null || 115 !$this->isFilteredRow($readFilter, $rowCoordinate, $columnsAttributes) 116 ) { 117 if (!isset($rowsAttributesAreSet[$rowCoordinate])) { 118 $this->setRowAttributes($rowCoordinate, $rowAttributes); 119 $rowsAttributesAreSet[$rowCoordinate] = true; 120 } 121 } 122 } 123 } 124 125 private function isFilteredColumn(IReadFilter $readFilter, string $columnCoordinate, array $rowsAttributes): bool 126 { 127 foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) { 128 if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) { 129 return true; 130 } 131 } 132 133 return false; 134 } 135 136 private function readColumnAttributes(SimpleXMLElement $worksheetCols, bool $readDataOnly): array 137 { 138 $columnAttributes = []; 139 140 foreach ($worksheetCols->col as $column) { 141 $startColumn = Coordinate::stringFromColumnIndex((int) $column['min']); 142 $endColumn = Coordinate::stringFromColumnIndex((int) $column['max']); 143 ++$endColumn; 144 for ($columnAddress = $startColumn; $columnAddress !== $endColumn; ++$columnAddress) { 145 $columnAttributes[$columnAddress] = $this->readColumnRangeAttributes($column, $readDataOnly); 146 147 if ((int) ($column['max']) == 16384) { 148 break; 149 } 150 } 151 } 152 153 return $columnAttributes; 154 } 155 156 private function readColumnRangeAttributes(SimpleXMLElement $column, bool $readDataOnly): array 157 { 158 $columnAttributes = []; 159 160 if ($column['style'] && !$readDataOnly) { 161 $columnAttributes['xfIndex'] = (int) $column['style']; 162 } 163 if (self::boolean($column['hidden'])) { 164 $columnAttributes['visible'] = false; 165 } 166 if (self::boolean($column['collapsed'])) { 167 $columnAttributes['collapsed'] = true; 168 } 169 if (((int) $column['outlineLevel']) > 0) { 170 $columnAttributes['outlineLevel'] = (int) $column['outlineLevel']; 171 } 172 $columnAttributes['width'] = (float) $column['width']; 173 174 return $columnAttributes; 175 } 176 177 private function isFilteredRow(IReadFilter $readFilter, int $rowCoordinate, array $columnsAttributes): bool 178 { 179 foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) { 180 if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) { 181 return true; 182 } 183 } 184 185 return false; 186 } 187 188 private function readRowAttributes(SimpleXMLElement $worksheetRow, bool $readDataOnly): array 189 { 190 $rowAttributes = []; 191 192 foreach ($worksheetRow as $row) { 193 if ($row['ht'] && !$readDataOnly) { 194 $rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht']; 195 } 196 if (self::boolean($row['hidden'])) { 197 $rowAttributes[(int) $row['r']]['visible'] = false; 198 } 199 if (self::boolean($row['collapsed'])) { 200 $rowAttributes[(int) $row['r']]['collapsed'] = true; 201 } 202 if ((int) $row['outlineLevel'] > 0) { 203 $rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel']; 204 } 205 if ($row['s'] && !$readDataOnly) { 206 $rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s']; 207 } 208 } 209 210 return $rowAttributes; 211 } 212 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body