PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.9
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.9
4.0.9 4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 All 150 releases
visualizer / vendor / openspout / openspout / src / Reader / ODS / SheetIterator.php

SheetIterator.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 4.0.9, at vendor/openspout/openspout/src/Reader/ODS/SheetIterator.php

240 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace OpenSpout\Reader\ODS;
4
5 use OpenSpout\Common\Exception\IOException;
6 use OpenSpout\Reader\Exception\XMLProcessingException;
7 use OpenSpout\Reader\IteratorInterface;
8 use OpenSpout\Reader\ODS\Creator\InternalEntityFactory;
9 use OpenSpout\Reader\ODS\Helper\SettingsHelper;
10 use OpenSpout\Reader\Wrapper\XMLReader;
11
12 /**
13 * Iterate over ODS sheet.
14 */
15 class SheetIterator implements IteratorInterface
16 {
17 public const CONTENT_XML_FILE_PATH = 'content.xml';
18
19 public const XML_STYLE_NAMESPACE = 'urn:oasis:names:tc:opendocument:xmlns:style:1.0';
20
21 /** Definition of XML nodes name and attribute used to parse sheet data */
22 public const XML_NODE_AUTOMATIC_STYLES = 'office:automatic-styles';
23 public const XML_NODE_STYLE_TABLE_PROPERTIES = 'table-properties';
24 public const XML_NODE_TABLE = 'table:table';
25 public const XML_ATTRIBUTE_STYLE_NAME = 'style:name';
26 public const XML_ATTRIBUTE_TABLE_NAME = 'table:name';
27 public const XML_ATTRIBUTE_TABLE_STYLE_NAME = 'table:style-name';
28 public const XML_ATTRIBUTE_TABLE_DISPLAY = 'table:display';
29
30 /** @var string Path of the file to be read */
31 protected $filePath;
32
33 /** @var \OpenSpout\Common\Manager\OptionsManagerInterface Reader's options manager */
34 protected $optionsManager;
35
36 /** @var InternalEntityFactory Factory to create entities */
37 protected $entityFactory;
38
39 /** @var XMLReader The XMLReader object that will help read sheet's XML data */
40 protected $xmlReader;
41
42 /** @var \OpenSpout\Common\Helper\Escaper\ODS Used to unescape XML data */
43 protected $escaper;
44
45 /** @var bool Whether there are still at least a sheet to be read */
46 protected $hasFoundSheet;
47
48 /** @var int The index of the sheet being read (zero-based) */
49 protected $currentSheetIndex;
50
51 /** @var string The name of the sheet that was defined as active */
52 protected $activeSheetName;
53
54 /** @var array Associative array [STYLE_NAME] => [IS_SHEET_VISIBLE] */
55 protected $sheetsVisibility;
56
57 /**
58 * @param string $filePath Path of the file to be read
59 * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager
60 * @param \OpenSpout\Common\Helper\Escaper\ODS $escaper Used to unescape XML data
61 * @param SettingsHelper $settingsHelper Helper to get data from "settings.xml"
62 * @param InternalEntityFactory $entityFactory Factory to create entities
63 */
64 public function __construct($filePath, $optionsManager, $escaper, $settingsHelper, $entityFactory)
65 {
66 $this->filePath = $filePath;
67 $this->optionsManager = $optionsManager;
68 $this->entityFactory = $entityFactory;
69 $this->xmlReader = $entityFactory->createXMLReader();
70 $this->escaper = $escaper;
71 $this->activeSheetName = $settingsHelper->getActiveSheetName($filePath);
72 }
73
74 /**
75 * Rewind the Iterator to the first element.
76 *
77 * @see http://php.net/manual/en/iterator.rewind.php
78 *
79 * @throws \OpenSpout\Common\Exception\IOException If unable to open the XML file containing sheets' data
80 */
81 #[\ReturnTypeWillChange]
82 public function rewind()
83 {
84 $this->xmlReader->close();
85
86 if (false === $this->xmlReader->openFileInZip($this->filePath, self::CONTENT_XML_FILE_PATH)) {
87 $contentXmlFilePath = $this->filePath.'#'.self::CONTENT_XML_FILE_PATH;
88
89 throw new IOException("Could not open \"{$contentXmlFilePath}\".");
90 }
91
92 try {
93 $this->sheetsVisibility = $this->readSheetsVisibility();
94 $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE);
95 } catch (XMLProcessingException $exception) {
96 throw new IOException("The content.xml file is invalid and cannot be read. [{$exception->getMessage()}]");
97 }
98
99 $this->currentSheetIndex = 0;
100 }
101
102 /**
103 * Checks if current position is valid.
104 *
105 * @see http://php.net/manual/en/iterator.valid.php
106 *
107 * @return bool
108 */
109 #[\ReturnTypeWillChange]
110 public function valid()
111 {
112 return $this->hasFoundSheet;
113 }
114
115 /**
116 * Move forward to next element.
117 *
118 * @see http://php.net/manual/en/iterator.next.php
119 */
120 #[\ReturnTypeWillChange]
121 public function next()
122 {
123 $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE);
124
125 if ($this->hasFoundSheet) {
126 ++$this->currentSheetIndex;
127 }
128 }
129
130 /**
131 * Return the current element.
132 *
133 * @see http://php.net/manual/en/iterator.current.php
134 *
135 * @return \OpenSpout\Reader\ODS\Sheet
136 */
137 #[\ReturnTypeWillChange]
138 public function current()
139 {
140 $escapedSheetName = $this->xmlReader->getAttribute(self::XML_ATTRIBUTE_TABLE_NAME);
141 $sheetName = $this->escaper->unescape($escapedSheetName);
142
143 $isSheetActive = $this->isSheetActive($sheetName, $this->currentSheetIndex, $this->activeSheetName);
144
145 $sheetStyleName = $this->xmlReader->getAttribute(self::XML_ATTRIBUTE_TABLE_STYLE_NAME);
146 $isSheetVisible = $this->isSheetVisible($sheetStyleName);
147
148 return $this->entityFactory->createSheet(
149 $this->xmlReader,
150 $this->currentSheetIndex,
151 $sheetName,
152 $isSheetActive,
153 $isSheetVisible,
154 $this->optionsManager
155 );
156 }
157
158 /**
159 * Return the key of the current element.
160 *
161 * @see http://php.net/manual/en/iterator.key.php
162 *
163 * @return int
164 */
165 #[\ReturnTypeWillChange]
166 public function key()
167 {
168 return $this->currentSheetIndex + 1;
169 }
170
171 /**
172 * Cleans up what was created to iterate over the object.
173 */
174 #[\ReturnTypeWillChange]
175 public function end()
176 {
177 $this->xmlReader->close();
178 }
179
180 /**
181 * Extracts the visibility of the sheets.
182 *
183 * @return array Associative array [STYLE_NAME] => [IS_SHEET_VISIBLE]
184 */
185 private function readSheetsVisibility()
186 {
187 $sheetsVisibility = [];
188
189 $this->xmlReader->readUntilNodeFound(self::XML_NODE_AUTOMATIC_STYLES);
190 /** @var \DOMElement $automaticStylesNode */
191 $automaticStylesNode = $this->xmlReader->expand();
192
193 $tableStyleNodes = $automaticStylesNode->getElementsByTagNameNS(self::XML_STYLE_NAMESPACE, self::XML_NODE_STYLE_TABLE_PROPERTIES);
194
195 /** @var \DOMElement $tableStyleNode */
196 foreach ($tableStyleNodes as $tableStyleNode) {
197 $isSheetVisible = ('false' !== $tableStyleNode->getAttribute(self::XML_ATTRIBUTE_TABLE_DISPLAY));
198
199 $parentStyleNode = $tableStyleNode->parentNode;
200 $styleName = $parentStyleNode->getAttribute(self::XML_ATTRIBUTE_STYLE_NAME);
201
202 $sheetsVisibility[$styleName] = $isSheetVisible;
203 }
204
205 return $sheetsVisibility;
206 }
207
208 /**
209 * Returns whether the current sheet was defined as the active one.
210 *
211 * @param string $sheetName Name of the current sheet
212 * @param int $sheetIndex Index of the current sheet
213 * @param null|string $activeSheetName Name of the sheet that was defined as active or NULL if none defined
214 *
215 * @return bool Whether the current sheet was defined as the active one
216 */
217 private function isSheetActive($sheetName, $sheetIndex, $activeSheetName)
218 {
219 // The given sheet is active if its name matches the defined active sheet's name
220 // or if no information about the active sheet was found, it defaults to the first sheet.
221 return
222 (null === $activeSheetName && 0 === $sheetIndex)
223 || ($activeSheetName === $sheetName)
224 ;
225 }
226
227 /**
228 * Returns whether the current sheet is visible.
229 *
230 * @param string $sheetStyleName Name of the sheet style
231 *
232 * @return bool Whether the current sheet is visible
233 */
234 private function isSheetVisible($sheetStyleName)
235 {
236 return $this->sheetsVisibility[$sheetStyleName] ??
237 true;
238 }
239 }
240