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 / XLSX / Helper / StyleHelper.php

StyleHelper.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.5, at app/Services/Spout/Writer/XLSX/Helper/StyleHelper.php

345 lines 10.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\XLSX\Helper;
4
5 use Box\Spout\Writer\Common\Helper\AbstractStyleHelper;
6 use Box\Spout\Writer\Style\Color;
7 use Box\Spout\Writer\Style\Style;
8
9 /**
10 * Class StyleHelper
11 * This class provides helper functions to manage styles
12 *
13 * @package Box\Spout\Writer\XLSX\Helper
14 */
15 class StyleHelper extends AbstractStyleHelper
16 {
17 /**
18 * @var array
19 */
20 protected $registeredFills = [];
21
22 /**
23 * @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
24 */
25 protected $styleIdToFillMappingTable = [];
26
27 /**
28 * Excel preserves two default fills with index 0 and 1
29 * Since Excel is the dominant vendor - we play along here
30 *
31 * @var int The fill index counter for custom fills.
32 */
33 protected $fillIndex = 2;
34
35 /**
36 * @var array
37 */
38 protected $registeredBorders = [];
39
40 /**
41 * @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration
42 */
43 protected $styleIdToBorderMappingTable = [];
44
45 /**
46 * XLSX specific operations on the registered styles
47 *
48 * @param \Box\Spout\Writer\Style\Style $style
49 * @return \Box\Spout\Writer\Style\Style
50 */
51 public function registerStyle($style)
52 {
53 $registeredStyle = parent::registerStyle($style);
54 $this->registerFill($registeredStyle);
55 $this->registerBorder($registeredStyle);
56 return $registeredStyle;
57 }
58
59 /**
60 * Register a fill definition
61 *
62 * @param \Box\Spout\Writer\Style\Style $style
63 */
64 protected function registerFill($style)
65 {
66 $styleId = $style->getId();
67
68 // Currently - only solid backgrounds are supported
69 // so $backgroundColor is a scalar value (RGB Color)
70 $backgroundColor = $style->getBackgroundColor();
71
72 if ($backgroundColor) {
73 $isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]);
74
75 // We need to track the already registered background definitions
76 if ($isBackgroundColorRegistered) {
77 $registeredStyleId = $this->registeredFills[$backgroundColor];
78 $registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId];
79 $this->styleIdToFillMappingTable[$styleId] = $registeredFillId;
80 } else {
81 $this->registeredFills[$backgroundColor] = $styleId;
82 $this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++;
83 }
84
85 } else {
86 // The fillId maps a style to a fill declaration
87 // When there is no background color definition - we default to 0
88 $this->styleIdToFillMappingTable[$styleId] = 0;
89 }
90 }
91
92 /**
93 * Register a border definition
94 *
95 * @param \Box\Spout\Writer\Style\Style $style
96 */
97 protected function registerBorder($style)
98 {
99 $styleId = $style->getId();
100
101 if ($style->shouldApplyBorder()) {
102 $border = $style->getBorder();
103 $serializedBorder = serialize($border);
104
105 $isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]);
106
107 if ($isBorderAlreadyRegistered) {
108 $registeredStyleId = $this->registeredBorders[$serializedBorder];
109 $registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId];
110 $this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId;
111 } else {
112 $this->registeredBorders[$serializedBorder] = $styleId;
113 $this->styleIdToBorderMappingTable[$styleId] = count($this->registeredBorders);
114 }
115
116 } else {
117 // If no border should be applied - the mapping is the default border: 0
118 $this->styleIdToBorderMappingTable[$styleId] = 0;
119 }
120 }
121
122
123 /**
124 * For empty cells, we can specify a style or not. If no style are specified,
125 * then the software default will be applied. But sometimes, it may be useful
126 * to override this default style, for instance if the cell should have a
127 * background color different than the default one or some borders
128 * (fonts property don't really matter here).
129 *
130 * @param int $styleId
131 * @return bool Whether the cell should define a custom style
132 */
133 public function shouldApplyStyleOnEmptyCell($styleId)
134 {
135 $hasStyleCustomFill = (isset($this->styleIdToFillMappingTable[$styleId]) && $this->styleIdToFillMappingTable[$styleId] !== 0);
136 $hasStyleCustomBorders = (isset($this->styleIdToBorderMappingTable[$styleId]) && $this->styleIdToBorderMappingTable[$styleId] !== 0);
137
138 return ($hasStyleCustomFill || $hasStyleCustomBorders);
139 }
140
141
142 /**
143 * Returns the content of the "styles.xml" file, given a list of styles.
144 *
145 * @return string
146 */
147 public function getStylesXMLFileContent()
148 {
149 $content = <<<EOD
150 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
151 <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
152 EOD;
153
154 $content .= $this->getFontsSectionContent();
155 $content .= $this->getFillsSectionContent();
156 $content .= $this->getBordersSectionContent();
157 $content .= $this->getCellStyleXfsSectionContent();
158 $content .= $this->getCellXfsSectionContent();
159 $content .= $this->getCellStylesSectionContent();
160
161 $content .= <<<EOD
162 </styleSheet>
163 EOD;
164
165 return $content;
166 }
167
168 /**
169 * Returns the content of the "<fonts>" section.
170 *
171 * @return string
172 */
173 protected function getFontsSectionContent()
174 {
175 $content = '<fonts count="' . count($this->styleIdToStyleMappingTable) . '">';
176
177 /** @var \Box\Spout\Writer\Style\Style $style */
178 foreach ($this->getRegisteredStyles() as $style) {
179 $content .= '<font>';
180
181 $content .= '<sz val="' . $style->getFontSize() . '"/>';
182 $content .= '<color rgb="' . Color::toARGB($style->getFontColor()) . '"/>';
183 $content .= '<name val="' . $style->getFontName() . '"/>';
184
185 if ($style->isFontBold()) {
186 $content .= '<b/>';
187 }
188 if ($style->isFontItalic()) {
189 $content .= '<i/>';
190 }
191 if ($style->isFontUnderline()) {
192 $content .= '<u/>';
193 }
194 if ($style->isFontStrikethrough()) {
195 $content .= '<strike/>';
196 }
197
198 $content .= '</font>';
199 }
200
201 $content .= '</fonts>';
202
203 return $content;
204 }
205
206 /**
207 * Returns the content of the "<fills>" section.
208 *
209 * @return string
210 */
211 protected function getFillsSectionContent()
212 {
213 // Excel reserves two default fills
214 $fillsCount = count($this->registeredFills) + 2;
215 $content = sprintf('<fills count="%d">', $fillsCount);
216
217 $content .= '<fill><patternFill patternType="none"/></fill>';
218 $content .= '<fill><patternFill patternType="gray125"/></fill>';
219
220 // The other fills are actually registered by setting a background color
221 foreach ($this->registeredFills as $styleId) {
222 /** @var Style $style */
223 $style = $this->styleIdToStyleMappingTable[$styleId];
224
225 $backgroundColor = $style->getBackgroundColor();
226 $content .= sprintf(
227 '<fill><patternFill patternType="solid"><fgColor rgb="%s"/></patternFill></fill>',
228 $backgroundColor
229 );
230 }
231
232 $content .= '</fills>';
233
234 return $content;
235 }
236
237 /**
238 * Returns the content of the "<borders>" section.
239 *
240 * @return string
241 */
242 protected function getBordersSectionContent()
243 {
244
245 // There is one default border with index 0
246 $borderCount = count($this->registeredBorders) + 1;
247
248 $content = '<borders count="' . $borderCount . '">';
249
250 // Default border starting at index 0
251 $content .= '<border><left/><right/><top/><bottom/></border>';
252
253 foreach ($this->registeredBorders as $styleId) {
254 /** @var \Box\Spout\Writer\Style\Style $style */
255 $style = $this->styleIdToStyleMappingTable[$styleId];
256 $border = $style->getBorder();
257 $content .= '<border>';
258
259 // @link https://github.com/box/spout/issues/271
260 $sortOrder = ['left', 'right', 'top', 'bottom'];
261
262 foreach ($sortOrder as $partName) {
263 if ($border->hasPart($partName)) {
264 /** @var $part \Box\Spout\Writer\Style\BorderPart */
265 $part = $border->getPart($partName);
266 $content .= BorderHelper::serializeBorderPart($part);
267 }
268
269 }
270
271 $content .= '</border>';
272 }
273
274 $content .= '</borders>';
275
276 return $content;
277 }
278
279 /**
280 * Returns the content of the "<cellStyleXfs>" section.
281 *
282 * @return string
283 */
284 protected function getCellStyleXfsSectionContent()
285 {
286 return <<<EOD
287 <cellStyleXfs count="1">
288 <xf borderId="0" fillId="0" fontId="0" numFmtId="0"/>
289 </cellStyleXfs>
290 EOD;
291 }
292
293 /**
294 * Returns the content of the "<cellXfs>" section.
295 *
296 * @return string
297 */
298 protected function getCellXfsSectionContent()
299 {
300 $registeredStyles = $this->getRegisteredStyles();
301
302 $content = '<cellXfs count="' . count($registeredStyles) . '">';
303
304 foreach ($registeredStyles as $style) {
305 $styleId = $style->getId();
306 $fillId = $this->styleIdToFillMappingTable[$styleId];
307 $borderId = $this->styleIdToBorderMappingTable[$styleId];
308
309 $content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"';
310
311 if ($style->shouldApplyFont()) {
312 $content .= ' applyFont="1"';
313 }
314
315 $content .= sprintf(' applyBorder="%d"', $style->shouldApplyBorder() ? 1 : 0);
316
317 if ($style->shouldWrapText()) {
318 $content .= ' applyAlignment="1">';
319 $content .= '<alignment wrapText="1"/>';
320 $content .= '</xf>';
321 } else {
322 $content .= '/>';
323 }
324 }
325
326 $content .= '</cellXfs>';
327
328 return $content;
329 }
330
331 /**
332 * Returns the content of the "<cellStyles>" section.
333 *
334 * @return string
335 */
336 protected function getCellStylesSectionContent()
337 {
338 return <<<EOD
339 <cellStyles count="1">
340 <cellStyle builtinId="0" name="Normal" xfId="0"/>
341 </cellStyles>
342 EOD;
343 }
344 }
345