Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 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
    private Worksheet $worksheet;
14
 
15
    private ?SimpleXMLElement $worksheetXml;
16
 
17
    public function __construct(Worksheet $workSheet, ?SimpleXMLElement $worksheetXml = null)
18
    {
19
        $this->worksheet = $workSheet;
20
        $this->worksheetXml = $worksheetXml;
21
    }
22
 
23
    /**
24
     * Set Worksheet column attributes by attributes array passed.
25
     *
26
     * @param string $columnAddress A, B, ... DX, ...
27
     * @param array $columnAttributes array of attributes (indexes are attribute name, values are value)
28
     *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ?
29
     */
30
    private function setColumnAttributes(string $columnAddress, array $columnAttributes): void
31
    {
32
        if (isset($columnAttributes['xfIndex'])) {
33
            $this->worksheet->getColumnDimension($columnAddress)->setXfIndex($columnAttributes['xfIndex']);
34
        }
35
        if (isset($columnAttributes['visible'])) {
36
            $this->worksheet->getColumnDimension($columnAddress)->setVisible($columnAttributes['visible']);
37
        }
38
        if (isset($columnAttributes['collapsed'])) {
39
            $this->worksheet->getColumnDimension($columnAddress)->setCollapsed($columnAttributes['collapsed']);
40
        }
41
        if (isset($columnAttributes['outlineLevel'])) {
42
            $this->worksheet->getColumnDimension($columnAddress)->setOutlineLevel($columnAttributes['outlineLevel']);
43
        }
44
        if (isset($columnAttributes['width'])) {
45
            $this->worksheet->getColumnDimension($columnAddress)->setWidth($columnAttributes['width']);
46
        }
47
    }
48
 
49
    /**
50
     * Set Worksheet row attributes by attributes array passed.
51
     *
52
     * @param int $rowNumber 1, 2, 3, ... 99, ...
53
     * @param array $rowAttributes array of attributes (indexes are attribute name, values are value)
54
     *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ?
55
     */
56
    private function setRowAttributes(int $rowNumber, array $rowAttributes): void
57
    {
58
        if (isset($rowAttributes['xfIndex'])) {
59
            $this->worksheet->getRowDimension($rowNumber)->setXfIndex($rowAttributes['xfIndex']);
60
        }
61
        if (isset($rowAttributes['visible'])) {
62
            $this->worksheet->getRowDimension($rowNumber)->setVisible($rowAttributes['visible']);
63
        }
64
        if (isset($rowAttributes['collapsed'])) {
65
            $this->worksheet->getRowDimension($rowNumber)->setCollapsed($rowAttributes['collapsed']);
66
        }
67
        if (isset($rowAttributes['outlineLevel'])) {
68
            $this->worksheet->getRowDimension($rowNumber)->setOutlineLevel($rowAttributes['outlineLevel']);
69
        }
70
        if (isset($rowAttributes['rowHeight'])) {
71
            $this->worksheet->getRowDimension($rowNumber)->setRowHeight($rowAttributes['rowHeight']);
72
        }
73
    }
74
 
75
    public function load(?IReadFilter $readFilter = null, bool $readDataOnly = false, bool $ignoreRowsWithNoCells = false): void
76
    {
77
        if ($this->worksheetXml === null) {
78
            return;
79
        }
80
 
81
        $columnsAttributes = [];
82
        $rowsAttributes = [];
83
        if (isset($this->worksheetXml->cols)) {
84
            $columnsAttributes = $this->readColumnAttributes($this->worksheetXml->cols, $readDataOnly);
85
        }
86
 
87
        if ($this->worksheetXml->sheetData && $this->worksheetXml->sheetData->row) {
88
            $rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly, $ignoreRowsWithNoCells);
89
        }
90
 
91
        if ($readFilter !== null && $readFilter::class === DefaultReadFilter::class) {
92
            $readFilter = null;
93
        }
94
 
95
        // set columns/rows attributes
96
        $columnsAttributesAreSet = [];
97
        foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) {
98
            if (
99
                $readFilter === null
100
                || !$this->isFilteredColumn($readFilter, $columnCoordinate, $rowsAttributes)
101
            ) {
102
                if (!isset($columnsAttributesAreSet[$columnCoordinate])) {
103
                    $this->setColumnAttributes($columnCoordinate, $columnAttributes);
104
                    $columnsAttributesAreSet[$columnCoordinate] = true;
105
                }
106
            }
107
        }
108
 
109
        $rowsAttributesAreSet = [];
110
        foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) {
111
            if (
112
                $readFilter === null
113
                || !$this->isFilteredRow($readFilter, $rowCoordinate, $columnsAttributes)
114
            ) {
115
                if (!isset($rowsAttributesAreSet[$rowCoordinate])) {
116
                    $this->setRowAttributes($rowCoordinate, $rowAttributes);
117
                    $rowsAttributesAreSet[$rowCoordinate] = true;
118
                }
119
            }
120
        }
121
    }
122
 
123
    private function isFilteredColumn(IReadFilter $readFilter, string $columnCoordinate, array $rowsAttributes): bool
124
    {
125
        foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) {
126
            if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) {
127
                return true;
128
            }
129
        }
130
 
131
        return false;
132
    }
133
 
134
    private function readColumnAttributes(SimpleXMLElement $worksheetCols, bool $readDataOnly): array
135
    {
136
        $columnAttributes = [];
137
 
138
        foreach ($worksheetCols->col as $columnx) {
139
            $column = $columnx->attributes();
140
            if ($column !== null) {
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
 
154
        return $columnAttributes;
155
    }
156
 
157
    private function readColumnRangeAttributes(?SimpleXMLElement $column, bool $readDataOnly): array
158
    {
159
        $columnAttributes = [];
160
        if ($column !== null) {
161
            if (isset($column['style']) && !$readDataOnly) {
162
                $columnAttributes['xfIndex'] = (int) $column['style'];
163
            }
164
            if (isset($column['hidden']) && self::boolean($column['hidden'])) {
165
                $columnAttributes['visible'] = false;
166
            }
167
            if (isset($column['collapsed']) && self::boolean($column['collapsed'])) {
168
                $columnAttributes['collapsed'] = true;
169
            }
170
            if (isset($column['outlineLevel']) && ((int) $column['outlineLevel']) > 0) {
171
                $columnAttributes['outlineLevel'] = (int) $column['outlineLevel'];
172
            }
173
            if (isset($column['width'])) {
174
                $columnAttributes['width'] = (float) $column['width'];
175
            }
176
        }
177
 
178
        return $columnAttributes;
179
    }
180
 
181
    private function isFilteredRow(IReadFilter $readFilter, int $rowCoordinate, array $columnsAttributes): bool
182
    {
183
        foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) {
184
            if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) {
185
                return true;
186
            }
187
        }
188
 
189
        return false;
190
    }
191
 
192
    private function readRowAttributes(SimpleXMLElement $worksheetRow, bool $readDataOnly, bool $ignoreRowsWithNoCells): array
193
    {
194
        $rowAttributes = [];
195
 
196
        foreach ($worksheetRow as $rowx) {
197
            $row = $rowx->attributes();
198
            if ($row !== null && (!$ignoreRowsWithNoCells || isset($rowx->c))) {
199
                if (isset($row['ht']) && !$readDataOnly) {
200
                    $rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
201
                }
202
                if (isset($row['hidden']) && self::boolean($row['hidden'])) {
203
                    $rowAttributes[(int) $row['r']]['visible'] = false;
204
                }
205
                if (isset($row['collapsed']) && self::boolean($row['collapsed'])) {
206
                    $rowAttributes[(int) $row['r']]['collapsed'] = true;
207
                }
208
                if (isset($row['outlineLevel']) && (int) $row['outlineLevel'] > 0) {
209
                    $rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
210
                }
211
                if (isset($row['s']) && !$readDataOnly) {
212
                    $rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
213
                }
214
            }
215
        }
216
 
217
        return $rowAttributes;
218
    }
219
}