PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.4
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / vendor / openspout / openspout / src / Reader / ODS / Helper / CellValueFormatter.php

CellValueFormatter.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.5.4, at vendor/openspout/openspout/src/Reader/ODS/Helper/CellValueFormatter.php

267 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\OpenSpout\Reader\ODS\Helper;
4
5 use FluentCart\OpenSpout\Reader\Exception\InvalidValueException;
6 /**
7 * This class provides helper functions to format cell values.
8 */
9 class CellValueFormatter
10 {
11 /** Definition of all possible cell types */
12 public const CELL_TYPE_STRING = 'string';
13 public const CELL_TYPE_FLOAT = 'float';
14 public const CELL_TYPE_BOOLEAN = 'boolean';
15 public const CELL_TYPE_DATE = 'date';
16 public const CELL_TYPE_TIME = 'time';
17 public const CELL_TYPE_CURRENCY = 'currency';
18 public const CELL_TYPE_PERCENTAGE = 'percentage';
19 public const CELL_TYPE_VOID = 'void';
20 /** Definition of XML nodes names used to parse data */
21 public const XML_NODE_P = 'p';
22 public const XML_NODE_TEXT_A = 'text:a';
23 public const XML_NODE_TEXT_SPAN = 'text:span';
24 public const XML_NODE_TEXT_S = 'text:s';
25 public const XML_NODE_TEXT_TAB = 'text:tab';
26 public const XML_NODE_TEXT_LINE_BREAK = 'text:line-break';
27 /** Definition of XML attributes used to parse data */
28 public const XML_ATTRIBUTE_TYPE = 'office:value-type';
29 public const XML_ATTRIBUTE_VALUE = 'office:value';
30 public const XML_ATTRIBUTE_BOOLEAN_VALUE = 'office:boolean-value';
31 public const XML_ATTRIBUTE_DATE_VALUE = 'office:date-value';
32 public const XML_ATTRIBUTE_TIME_VALUE = 'office:time-value';
33 public const XML_ATTRIBUTE_CURRENCY = 'office:currency';
34 public const XML_ATTRIBUTE_C = 'text:c';
35 /** @var bool Whether date/time values should be returned as PHP objects or be formatted as strings */
36 protected $shouldFormatDates;
37 /** @var \OpenSpout\Common\Helper\Escaper\ODS Used to unescape XML data */
38 protected $escaper;
39 /** @var array List of XML nodes representing whitespaces and their corresponding value */
40 private static $WHITESPACE_XML_NODES = [self::XML_NODE_TEXT_S => ' ', self::XML_NODE_TEXT_TAB => "\t", self::XML_NODE_TEXT_LINE_BREAK => "\n"];
41 /**
42 * @param bool $shouldFormatDates Whether date/time values should be returned as PHP objects or be formatted as strings
43 * @param \OpenSpout\Common\Helper\Escaper\ODS $escaper Used to unescape XML data
44 */
45 public function __construct($shouldFormatDates, $escaper)
46 {
47 $this->shouldFormatDates = $shouldFormatDates;
48 $this->escaper = $escaper;
49 }
50 /**
51 * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node.
52 *
53 * @see http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#refTable13
54 *
55 * @param \DOMElement $node
56 *
57 * @throws InvalidValueException If the node value is not valid
58 *
59 * @return bool|\DateInterval|\DateTime|float|int|string The value associated with the cell, empty string if cell's type is void/undefined
60 */
61 public function extractAndFormatNodeValue($node)
62 {
63 $cellType = $node->getAttribute(self::XML_ATTRIBUTE_TYPE);
64 switch ($cellType) {
65 case self::CELL_TYPE_STRING:
66 return $this->formatStringCellValue($node);
67 case self::CELL_TYPE_FLOAT:
68 return $this->formatFloatCellValue($node);
69 case self::CELL_TYPE_BOOLEAN:
70 return $this->formatBooleanCellValue($node);
71 case self::CELL_TYPE_DATE:
72 return $this->formatDateCellValue($node);
73 case self::CELL_TYPE_TIME:
74 return $this->formatTimeCellValue($node);
75 case self::CELL_TYPE_CURRENCY:
76 return $this->formatCurrencyCellValue($node);
77 case self::CELL_TYPE_PERCENTAGE:
78 return $this->formatPercentageCellValue($node);
79 case self::CELL_TYPE_VOID:
80 default:
81 return '';
82 }
83 }
84 /**
85 * Returns the cell String value.
86 *
87 * @param \DOMElement $node
88 *
89 * @return string The value associated with the cell
90 */
91 protected function formatStringCellValue($node)
92 {
93 $pNodeValues = [];
94 $pNodes = $node->getElementsByTagName(self::XML_NODE_P);
95 foreach ($pNodes as $pNode) {
96 $pNodeValues[] = $this->extractTextValueFromNode($pNode);
97 }
98 $escapedCellValue = \implode("\n", $pNodeValues);
99 return $this->escaper->unescape($escapedCellValue);
100 }
101 /**
102 * Returns the cell Numeric value from the given node.
103 *
104 * @param \DOMElement $node
105 *
106 * @return float|int The value associated with the cell
107 */
108 protected function formatFloatCellValue($node)
109 {
110 $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_VALUE);
111 $nodeIntValue = (int) $nodeValue;
112 $nodeFloatValue = (float) $nodeValue;
113 return (float) $nodeIntValue === $nodeFloatValue ? $nodeIntValue : $nodeFloatValue;
114 }
115 /**
116 * Returns the cell Boolean value from the given node.
117 *
118 * @param \DOMElement $node
119 *
120 * @return bool The value associated with the cell
121 */
122 protected function formatBooleanCellValue($node)
123 {
124 $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_BOOLEAN_VALUE);
125 return (bool) $nodeValue;
126 }
127 /**
128 * Returns the cell Date value from the given node.
129 *
130 * @param \DOMElement $node
131 *
132 * @throws InvalidValueException If the value is not a valid date
133 *
134 * @return \DateTime|string The value associated with the cell
135 */
136 protected function formatDateCellValue($node)
137 {
138 // The XML node looks like this:
139 // <table:table-cell calcext:value-type="date" office:date-value="2016-05-19T16:39:00" office:value-type="date">
140 // <text:p>05/19/16 04:39 PM</text:p>
141 // </table:table-cell>
142 if ($this->shouldFormatDates) {
143 // The date is already formatted in the "p" tag
144 $nodeWithValueAlreadyFormatted = $node->getElementsByTagName(self::XML_NODE_P)->item(0);
145 $cellValue = $nodeWithValueAlreadyFormatted->nodeValue;
146 } else {
147 // otherwise, get it from the "date-value" attribute
148 $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_DATE_VALUE);
149 try {
150 $cellValue = new \DateTime($nodeValue);
151 } catch (\Exception $e) {
152 throw new InvalidValueException($nodeValue);
153 }
154 }
155 return $cellValue;
156 }
157 /**
158 * Returns the cell Time value from the given node.
159 *
160 * @param \DOMElement $node
161 *
162 * @throws InvalidValueException If the value is not a valid time
163 *
164 * @return \DateInterval|string The value associated with the cell
165 */
166 protected function formatTimeCellValue($node)
167 {
168 // The XML node looks like this:
169 // <table:table-cell calcext:value-type="time" office:time-value="PT13H24M00S" office:value-type="time">
170 // <text:p>01:24:00 PM</text:p>
171 // </table:table-cell>
172 if ($this->shouldFormatDates) {
173 // The date is already formatted in the "p" tag
174 $nodeWithValueAlreadyFormatted = $node->getElementsByTagName(self::XML_NODE_P)->item(0);
175 $cellValue = $nodeWithValueAlreadyFormatted->nodeValue;
176 } else {
177 // otherwise, get it from the "time-value" attribute
178 $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_TIME_VALUE);
179 try {
180 $cellValue = new \DateInterval($nodeValue);
181 } catch (\Exception $e) {
182 throw new InvalidValueException($nodeValue);
183 }
184 }
185 return $cellValue;
186 }
187 /**
188 * Returns the cell Currency value from the given node.
189 *
190 * @param \DOMElement $node
191 *
192 * @return string The value associated with the cell (e.g. "100 USD" or "9.99 EUR")
193 */
194 protected function formatCurrencyCellValue($node)
195 {
196 $value = $node->getAttribute(self::XML_ATTRIBUTE_VALUE);
197 $currency = $node->getAttribute(self::XML_ATTRIBUTE_CURRENCY);
198 return "{$value} {$currency}";
199 }
200 /**
201 * Returns the cell Percentage value from the given node.
202 *
203 * @param \DOMElement $node
204 *
205 * @return float|int The value associated with the cell
206 */
207 protected function formatPercentageCellValue($node)
208 {
209 // percentages are formatted like floats
210 return $this->formatFloatCellValue($node);
211 }
212 /**
213 * @param \DOMNode $pNode
214 *
215 * @return string
216 */
217 private function extractTextValueFromNode($pNode)
218 {
219 $textValue = '';
220 foreach ($pNode->childNodes as $childNode) {
221 if ($childNode instanceof \DOMText) {
222 $textValue .= $childNode->nodeValue;
223 } elseif ($this->isWhitespaceNode($childNode->nodeName)) {
224 $textValue .= $this->transformWhitespaceNode($childNode);
225 } elseif (self::XML_NODE_TEXT_A === $childNode->nodeName || self::XML_NODE_TEXT_SPAN === $childNode->nodeName) {
226 $textValue .= $this->extractTextValueFromNode($childNode);
227 }
228 }
229 return $textValue;
230 }
231 /**
232 * Returns whether the given node is a whitespace node. It must be one of these:
233 * - <text:s />
234 * - <text:tab />
235 * - <text:line-break />.
236 *
237 * @param string $nodeName
238 *
239 * @return bool
240 */
241 private function isWhitespaceNode($nodeName)
242 {
243 return isset(self::$WHITESPACE_XML_NODES[$nodeName]);
244 }
245 /**
246 * The "<text:p>" node can contain the string value directly
247 * or contain child elements. In this case, whitespaces contain in
248 * the child elements should be replaced by their XML equivalent:
249 * - space => <text:s />
250 * - tab => <text:tab />
251 * - line break => <text:line-break />.
252 *
253 * @see https://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1415200_253892949
254 *
255 * @param \DOMElement $node The XML node representing a whitespace
256 *
257 * @return string The corresponding whitespace value
258 */
259 private function transformWhitespaceNode($node)
260 {
261 $countAttribute = $node->getAttribute(self::XML_ATTRIBUTE_C);
262 // only defined for "<text:s>"
263 $numWhitespaces = !empty($countAttribute) ? (int) $countAttribute : 1;
264 return \str_repeat(self::$WHITESPACE_XML_NODES[$node->nodeName], $numWhitespaces);
265 }
266 }
267