PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.5
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.5
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Spout / Writer / ODS / Internal / Worksheet.php

Worksheet.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.5, at app/Services/Spout/Writer/ODS/Internal/Worksheet.php

234 lines 8.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Box\Spout\Writer\ODS\Internal;
4
5 use Box\Spout\Common\Exception\InvalidArgumentException;
6 use Box\Spout\Common\Exception\IOException;
7 use Box\Spout\Common\Helper\StringHelper;
8 use Box\Spout\Writer\Common\Helper\CellHelper;
9 use Box\Spout\Writer\Common\Internal\WorksheetInterface;
10
11 /**
12 * Class Worksheet
13 * Represents a worksheet within a ODS file. The difference with the Sheet object is
14 * that this class provides an interface to write data
15 *
16 * @package Box\Spout\Writer\ODS\Internal
17 */
18 class Worksheet implements WorksheetInterface
19 {
20 /** @var \Box\Spout\Writer\Common\Sheet The "external" sheet */
21 protected $externalSheet;
22
23 /** @var string Path to the XML file that will contain the sheet data */
24 protected $worksheetFilePath;
25
26 /** @var \Box\Spout\Common\Escaper\ODS Strings escaper */
27 protected $stringsEscaper;
28
29 /** @var \Box\Spout\Common\Helper\StringHelper To help with string manipulation */
30 protected $stringHelper;
31
32 /** @var Resource Pointer to the temporary sheet data file (e.g. worksheets-temp/sheet1.xml) */
33 protected $sheetFilePointer;
34
35 /** @var int Maximum number of columns among all the written rows */
36 protected $maxNumColumns = 1;
37
38 /** @var int Index of the last written row */
39 protected $lastWrittenRowIndex = 0;
40
41 /**
42 * @param \Box\Spout\Writer\Common\Sheet $externalSheet The associated "external" sheet
43 * @param string $worksheetFilesFolder Temporary folder where the files to create the ODS will be stored
44 * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
45 */
46 public function __construct($externalSheet, $worksheetFilesFolder)
47 {
48 $this->externalSheet = $externalSheet;
49 /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
50 $this->stringsEscaper = \Box\Spout\Common\Escaper\ODS::getInstance();
51 $this->worksheetFilePath = $worksheetFilesFolder . '/sheet' . $externalSheet->getIndex() . '.xml';
52
53 $this->stringHelper = new StringHelper();
54
55 $this->startSheet();
56 }
57
58 /**
59 * Prepares the worksheet to accept data
60 * The XML file does not contain the "<table:table>" node as it contains the sheet's name
61 * which may change during the execution of the program. It will be added at the end.
62 *
63 * @return void
64 * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
65 */
66 protected function startSheet()
67 {
68 $this->sheetFilePointer = fopen($this->worksheetFilePath, 'w');
69 $this->throwIfSheetFilePointerIsNotAvailable();
70 }
71
72 /**
73 * Checks if the book has been created. Throws an exception if not created yet.
74 *
75 * @return void
76 * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
77 */
78 protected function throwIfSheetFilePointerIsNotAvailable()
79 {
80 if (!$this->sheetFilePointer) {
81 throw new IOException('Unable to open sheet for writing.');
82 }
83 }
84
85 /**
86 * @return string Path to the temporary sheet content XML file
87 */
88 public function getWorksheetFilePath()
89 {
90 return $this->worksheetFilePath;
91 }
92
93 /**
94 * Returns the table XML root node as string.
95 *
96 * @return string <table> node as string
97 */
98 public function getTableElementStartAsString()
99 {
100 $escapedSheetName = $this->stringsEscaper->escape($this->externalSheet->getName());
101 $tableStyleName = 'ta' . ($this->externalSheet->getIndex() + 1);
102
103 $tableElement = '<table:table table:style-name="' . $tableStyleName . '" table:name="' . $escapedSheetName . '">';
104 $tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co1" table:number-columns-repeated="' . $this->maxNumColumns . '"/>';
105
106 return $tableElement;
107 }
108
109 /**
110 * @return \Box\Spout\Writer\Common\Sheet The "external" sheet
111 */
112 public function getExternalSheet()
113 {
114 return $this->externalSheet;
115 }
116
117 /**
118 * @return int The index of the last written row
119 */
120 public function getLastWrittenRowIndex()
121 {
122 return $this->lastWrittenRowIndex;
123 }
124
125 /**
126 * Adds data to the worksheet.
127 *
128 * @param array $dataRow Array containing data to be written. Cannot be empty.
129 * Example $dataRow = ['data1', 1234, null, '', 'data5'];
130 * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style.
131 * @return void
132 * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written
133 * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported
134 */
135 public function addRow($dataRow, $style)
136 {
137 // $dataRow can be an associative array. We need to transform
138 // it into a regular array, as we'll use the numeric indexes.
139 $dataRowWithNumericIndexes = array_values($dataRow);
140
141 $styleIndex = ($style->getId() + 1); // 1-based
142 $cellsCount = count($dataRow);
143 $this->maxNumColumns = max($this->maxNumColumns, $cellsCount);
144
145 $data = '<table:table-row table:style-name="ro1">';
146
147 $currentCellIndex = 0;
148 $nextCellIndex = 1;
149
150 for ($i = 0; $i < $cellsCount; $i++) {
151 $currentCellValue = $dataRowWithNumericIndexes[$currentCellIndex];
152
153 // Using isset here because it is way faster than array_key_exists...
154 if (!isset($dataRowWithNumericIndexes[$nextCellIndex]) ||
155 $currentCellValue !== $dataRowWithNumericIndexes[$nextCellIndex]) {
156
157 $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex);
158 $data .= $this->getCellXML($currentCellValue, $styleIndex, $numTimesValueRepeated);
159
160 $currentCellIndex = $nextCellIndex;
161 }
162
163 $nextCellIndex++;
164 }
165
166 $data .= '</table:table-row>';
167
168 $wasWriteSuccessful = fwrite($this->sheetFilePointer, $data);
169 if ($wasWriteSuccessful === false) {
170 throw new IOException("Unable to write data in {$this->worksheetFilePath}");
171 }
172
173 // only update the count if the write worked
174 $this->lastWrittenRowIndex++;
175 }
176
177 /**
178 * Returns the cell XML content, given its value.
179 *
180 * @param mixed $cellValue The value to be written
181 * @param int $styleIndex Index of the used style
182 * @param int $numTimesValueRepeated Number of times the value is consecutively repeated
183 * @return string The cell XML content
184 * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported
185 */
186 protected function getCellXML($cellValue, $styleIndex, $numTimesValueRepeated)
187 {
188 $data = '<table:table-cell table:style-name="ce' . $styleIndex . '"';
189
190 if ($numTimesValueRepeated !== 1) {
191 $data .= ' table:number-columns-repeated="' . $numTimesValueRepeated . '"';
192 }
193
194 if (CellHelper::isNonEmptyString($cellValue)) {
195 $data .= ' office:value-type="string" calcext:value-type="string">';
196
197 $cellValueLines = explode("\n", $cellValue);
198 foreach ($cellValueLines as $cellValueLine) {
199 $data .= '<text:p>' . $this->stringsEscaper->escape($cellValueLine) . '</text:p>';
200 }
201
202 $data .= '</table:table-cell>';
203 } else if (CellHelper::isBoolean($cellValue)) {
204 $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $cellValue . '">';
205 $data .= '<text:p>' . $cellValue . '</text:p>';
206 $data .= '</table:table-cell>';
207 } else if (CellHelper::isNumeric($cellValue)) {
208 $data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cellValue . '">';
209 $data .= '<text:p>' . $cellValue . '</text:p>';
210 $data .= '</table:table-cell>';
211 } else if (empty($cellValue)) {
212 $data .= '/>';
213 } else {
214 throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cellValue));
215 }
216
217 return $data;
218 }
219
220 /**
221 * Closes the worksheet
222 *
223 * @return void
224 */
225 public function close()
226 {
227 if (!is_resource($this->sheetFilePointer)) {
228 return;
229 }
230
231 fclose($this->sheetFilePointer);
232 }
233 }
234