Failed Conditions
Pull Request — master (#715)
by
unknown
03:04
created

StyleManager::getMasterStylesSectionContent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 6
cts 6
cp 1
rs 9.6333
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Box\Spout\Writer\ODS\Manager\Style;
4
5
use Box\Spout\Common\Entity\Style\BorderPart;
6
use Box\Spout\Common\Entity\Style\CellAlignment;
7
use Box\Spout\Writer\Common\Entity\Worksheet;
8
use Box\Spout\Writer\Common\Manager\ManagesCellSize;
9
use Box\Spout\Writer\ODS\Helper\BorderHelper;
10
11
/**
12
 * Class StyleManager
13
 * Manages styles to be applied to a cell
14
 */
15
class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager
16
{
17
    use ManagesCellSize;
18
19
    /** @var StyleRegistry */
20
    protected $styleRegistry;
21
22
    /**
23
     * Returns the content of the "styles.xml" file, given a list of styles.
24
     *
25
     * @param int $numWorksheets Number of worksheets created
26
     * @return string
27
     */
28 39
    public function getStylesXMLFileContent($numWorksheets)
29
    {
30
        $content = <<<'EOD'
31 39
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
32
<office:document-styles office:version="1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:msoxl="http://schemas.microsoft.com/office/excel/formula" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink">
33
EOD;
34
35 39
        $content .= $this->getFontFaceSectionContent();
36 39
        $content .= $this->getStylesSectionContent();
37 39
        $content .= $this->getAutomaticStylesSectionContent($numWorksheets);
38 39
        $content .= $this->getMasterStylesSectionContent($numWorksheets);
39
40
        $content .= <<<'EOD'
41 39
</office:document-styles>
42
EOD;
43
44 39
        return $content;
45
    }
46
47
    /**
48
     * Returns the content of the "<office:font-face-decls>" section, inside "styles.xml" file.
49
     *
50
     * @return string
51
     */
52 39
    protected function getFontFaceSectionContent()
53
    {
54 39
        $content = '<office:font-face-decls>';
55 39
        foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
56 39
            $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>';
57
        }
58 39
        $content .= '</office:font-face-decls>';
59
60 39
        return $content;
61
    }
62
63
    /**
64
     * Returns the content of the "<office:styles>" section, inside "styles.xml" file.
65
     *
66
     * @return string
67
     */
68 39
    protected function getStylesSectionContent()
69
    {
70 39
        $defaultStyle = $this->getDefaultStyle();
71
72
        return <<<EOD
73
<office:styles>
74
    <number:number-style style:name="N0">
75
        <number:number number:min-integer-digits="1"/>
76
    </number:number-style>
77
    <style:style style:data-style-name="N0" style:family="table-cell" style:name="Default">
78
        <style:table-cell-properties fo:background-color="transparent" style:vertical-align="automatic"/>
79 39
        <style:text-properties fo:color="#{$defaultStyle->getFontColor()}"
80 39
                               fo:font-size="{$defaultStyle->getFontSize()}pt" style:font-size-asian="{$defaultStyle->getFontSize()}pt" style:font-size-complex="{$defaultStyle->getFontSize()}pt"
81 39
                               style:font-name="{$defaultStyle->getFontName()}" style:font-name-asian="{$defaultStyle->getFontName()}" style:font-name-complex="{$defaultStyle->getFontName()}"/>
82
    </style:style>
83
</office:styles>
84
EOD;
85
    }
86
87
    /**
88
     * Returns the content of the "<office:automatic-styles>" section, inside "styles.xml" file.
89
     *
90
     * @param int $numWorksheets Number of worksheets created
91
     * @return string
92
     */
93 39
    protected function getAutomaticStylesSectionContent($numWorksheets)
94
    {
95 39
        $content = '<office:automatic-styles>';
96
97 39
        for ($i = 1; $i <= $numWorksheets; $i++) {
98
            $content .= <<<EOD
99 39
<style:page-layout style:name="pm$i">
100
    <style:page-layout-properties style:first-page-number="continue" style:print="objects charts drawings" style:table-centering="none"/>
101
    <style:header-style/>
102
    <style:footer-style/>
103
</style:page-layout>
104
EOD;
105
        }
106
107 39
        $content .= '</office:automatic-styles>';
108
109 39
        return $content;
110
    }
111
112
    /**
113
     * Returns the content of the "<office:master-styles>" section, inside "styles.xml" file.
114
     *
115
     * @param int $numWorksheets Number of worksheets created
116
     * @return string
117
     */
118 39
    protected function getMasterStylesSectionContent($numWorksheets)
119
    {
120 39
        $content = '<office:master-styles>';
121
122 39
        for ($i = 1; $i <= $numWorksheets; $i++) {
123
            $content .= <<<EOD
124 39
<style:master-page style:name="mp$i" style:page-layout-name="pm$i">
125
    <style:header/>
126
    <style:header-left style:display="false"/>
127
    <style:footer/>
128
    <style:footer-left style:display="false"/>
129
</style:master-page>
130
EOD;
131
        }
132
133 39
        $content .= '</office:master-styles>';
134
135 39
        return $content;
136
    }
137
138
    /**
139
     * Returns the contents of the "<office:font-face-decls>" section, inside "content.xml" file.
140
     *
141
     * @return string
142
     */
143 39
    public function getContentXmlFontFaceSectionContent()
144
    {
145 39
        $content = '<office:font-face-decls>';
146 39
        foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
147 39
            $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>';
148
        }
149 39
        $content .= '</office:font-face-decls>';
150
151 39
        return $content;
152
    }
153
154
    /**
155
     * Returns the contents of the "<office:automatic-styles>" section, inside "content.xml" file.
156
     *
157
     * @param Worksheet[] $worksheets
158
     * @return string
159
     */
160 39
    public function getContentXmlAutomaticStylesSectionContent($worksheets)
161
    {
162 39
        $content = '<office:automatic-styles>';
163
164 39
        foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
165 39
            $content .= $this->getStyleSectionContent($style);
166
        }
167
168 39
        $useOptimalRowHeight = empty($this->defaultRowHeight) ? 'true' : 'false';
169 39
        $defaultRowHeight = empty($this->defaultRowHeight) ? '15pt' : "{$this->defaultRowHeight}pt";
170 39
        $defaultColumnWidth = empty($this->defaultColumnWidth) ? '' : "style:column-width=\"{$this->defaultColumnWidth}pt\"";
171
172
        $content .= <<<EOD
173
<style:style style:family="table-column" style:name="default-column-style">
174 39
    <style:table-column-properties fo:break-before="auto" {$defaultColumnWidth}/>
175
</style:style>
176
<style:style style:family="table-row" style:name="ro1">
177 39
    <style:table-row-properties fo:break-before="auto" style:row-height="{$defaultRowHeight}" style:use-optimal-row-height="{$useOptimalRowHeight}"/>
178
</style:style>
179
EOD;
180
181 39
        foreach ($worksheets as $worksheet) {
182 39
            $worksheetId = $worksheet->getId();
183 39
            $isSheetVisible = $worksheet->getExternalSheet()->isVisible() ? 'true' : 'false';
184
185
            $content .= <<<EOD
186 39
<style:style style:family="table" style:master-page-name="mp$worksheetId" style:name="ta$worksheetId">
187 39
    <style:table-properties style:writing-mode="lr-tb" table:display="$isSheetVisible"/>
188
</style:style>
189
EOD;
190
        }
191
192
        // Sort column widths since ODS cares about order
193
        usort($this->columnWidths, function ($a, $b) {
194 1
            if ($a[0] === $b[0]) {
195
                return 0;
196
            }
197
198 1
            return ($a[0] < $b[0]) ? -1 : 1;
199 39
        });
200 39
        $content .= $this->getTableColumnStylesXMLContent();
201
202 39
        $content .= '</office:automatic-styles>';
203
204 39
        return $content;
205
    }
206
207
    /**
208
     * Returns the contents of the "<style:style>" section, inside "<office:automatic-styles>" section
209
     *
210
     * @param \Box\Spout\Common\Entity\Style\Style $style
211
     * @return string
212
     */
213 39
    protected function getStyleSectionContent($style)
214
    {
215 39
        $styleIndex = $style->getId() + 1; // 1-based
216
217 39
        $content = '<style:style style:data-style-name="N0" style:family="table-cell" style:name="ce' . $styleIndex . '" style:parent-style-name="Default">';
218
219 39
        $content .= $this->getTextPropertiesSectionContent($style);
220 39
        $content .= $this->getParagraphPropertiesSectionContent($style);
221 39
        $content .= $this->getTableCellPropertiesSectionContent($style);
222
223 39
        $content .= '</style:style>';
224
225 39
        return $content;
226
    }
227
228
    /**
229
     * Returns the contents of the "<style:text-properties>" section, inside "<style:style>" section
230
     *
231
     * @param \Box\Spout\Common\Entity\Style\Style $style
232
     * @return string
233
     */
234 39
    private function getTextPropertiesSectionContent($style)
235
    {
236 39
        if (!$style->shouldApplyFont()) {
237 38
            return '';
238
        }
239
240
        return '<style:text-properties '
241 5
            . $this->getFontSectionContent($style)
242 5
            . '/>';
243
    }
244
245
    /**
246
     * Returns the contents of the fonts definition section, inside "<style:text-properties>" section
247
     *
248
     * @param \Box\Spout\Common\Entity\Style\Style $style
249
     *
250
     * @return string
251
     */
252 5
    private function getFontSectionContent($style)
253
    {
254 5
        $defaultStyle = $this->getDefaultStyle();
255 5
        $content = '';
256
257 5
        $fontColor = $style->getFontColor();
258 5
        if ($fontColor !== $defaultStyle->getFontColor()) {
259 1
            $content .= ' fo:color="#' . $fontColor . '"';
260
        }
261
262 5
        $fontName = $style->getFontName();
263 5
        if ($fontName !== $defaultStyle->getFontName()) {
264 1
            $content .= ' style:font-name="' . $fontName . '" style:font-name-asian="' . $fontName . '" style:font-name-complex="' . $fontName . '"';
265
        }
266
267 5
        $fontSize = $style->getFontSize();
268 5
        if ($fontSize !== $defaultStyle->getFontSize()) {
269 2
            $content .= ' fo:font-size="' . $fontSize . 'pt" style:font-size-asian="' . $fontSize . 'pt" style:font-size-complex="' . $fontSize . 'pt"';
270
        }
271
272 5
        if ($style->isFontBold()) {
273 4
            $content .= ' fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"';
274
        }
275 5
        if ($style->isFontItalic()) {
276 1
            $content .= ' fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"';
277
        }
278 5
        if ($style->isFontUnderline()) {
279 2
            $content .= ' style:text-underline-style="solid" style:text-underline-type="single"';
280
        }
281 5
        if ($style->isFontStrikethrough()) {
282 1
            $content .= ' style:text-line-through-style="solid"';
283
        }
284
285 5
        return $content;
286
    }
287
288
    /**
289
     * Returns the contents of the "<style:paragraph-properties>" section, inside "<style:style>" section
290
     *
291
     * @param \Box\Spout\Common\Entity\Style\Style $style
292
     *
293
     * @return string
294
     */
295 39
    private function getParagraphPropertiesSectionContent($style)
296
    {
297 39
        if (!$style->shouldApplyCellAlignment()) {
298 39
            return '';
299
        }
300
301
        return '<style:paragraph-properties '
302 1
            . $this->getCellAlignmentSectionContent($style)
303 1
            . '/>';
304
    }
305
306
    /**
307
     * Returns the contents of the cell alignment definition for the "<style:paragraph-properties>" section
308
     *
309
     * @param \Box\Spout\Common\Entity\Style\Style $style
310
     *
311
     * @return string
312
     */
313 1
    private function getCellAlignmentSectionContent($style)
314
    {
315 1
        return \sprintf(
316 1
            ' fo:text-align="%s" ',
317 1
            $this->transformCellAlignment($style->getCellAlignment())
318
        );
319
    }
320
321
    /**
322
     * Even though "left" and "right" alignments are part of the spec, and interpreted
323
     * respectively as "start" and "end", using the recommended values increase compatibility
324
     * with software that will read the created ODS file.
325
     *
326
     * @param string $cellAlignment
327
     *
328
     * @return string
329
     */
330 1
    private function transformCellAlignment($cellAlignment)
331
    {
332
        switch ($cellAlignment) {
333 1
            case CellAlignment::LEFT:
334
                return 'start';
335 1
            case CellAlignment::RIGHT:
336 1
                return 'end';
337
            default:
338
                return $cellAlignment;
339
        }
340
    }
341
342
    /**
343
     * Returns the contents of the "<style:table-cell-properties>" section, inside "<style:style>" section
344
     *
345
     * @param \Box\Spout\Common\Entity\Style\Style $style
346
     * @return string
347
     */
348 39
    private function getTableCellPropertiesSectionContent($style)
349
    {
350 39
        $content = '<style:table-cell-properties ';
351
352 39
        if ($style->shouldWrapText()) {
353 3
            $content .= $this->getWrapTextXMLContent();
354
        }
355
356 39
        if ($style->shouldApplyBorder()) {
357 1
            $content .= $this->getBorderXMLContent($style);
358
        }
359
360 39
        if ($style->shouldApplyBackgroundColor()) {
361 2
            $content .= $this->getBackgroundColorXMLContent($style);
362
        }
363
364 39
        $content .= '/>';
365
366 39
        return $content;
367
    }
368
369
    /**
370
     * Returns the contents of the wrap text definition for the "<style:table-cell-properties>" section
371
     *
372
     * @return string
373
     */
374 3
    private function getWrapTextXMLContent()
375
    {
376 3
        return ' fo:wrap-option="wrap" style:vertical-align="automatic" ';
377
    }
378
379
    /**
380
     * Returns the contents of the borders definition for the "<style:table-cell-properties>" section
381
     *
382
     * @param \Box\Spout\Common\Entity\Style\Style $style
383
     * @return string
384
     */
385 1
    private function getBorderXMLContent($style)
386
    {
387
        $borders = \array_map(function (BorderPart $borderPart) {
388 1
            return BorderHelper::serializeBorderPart($borderPart);
389 1
        }, $style->getBorder()->getParts());
390
391 1
        return \sprintf(' %s ', \implode(' ', $borders));
392
    }
393
394
    /**
395
     * Returns the contents of the background color definition for the "<style:table-cell-properties>" section
396
     *
397
     * @param \Box\Spout\Common\Entity\Style\Style $style
398
     * @return string
399
     */
400 2
    private function getBackgroundColorXMLContent($style)
401
    {
402 2
        return \sprintf(' fo:background-color="#%s" ', $style->getBackgroundColor());
403
    }
404
405 39
    public function getTableColumnStylesXMLContent() : string
406
    {
407 39
        if (empty($this->columnWidths)) {
408 35
            return '';
409
        }
410
411 4
        $content = '';
412 4
        foreach ($this->columnWidths as $styleIndex => $entry) {
413
            $content .= <<<EOD
414 4
<style:style style:family="table-column" style:name="co{$styleIndex}">
415 4
    <style:table-column-properties fo:break-before="auto" style:use-optimal-column-width="false" style:column-width="{$entry[2]}pt"/>
416
</style:style>
417
EOD;
418
        }
419
420 4
        return $content;
421
    }
422
423 39
    public function getStyledTableColumnXMLContent(int $maxNumColumns) : string
424
    {
425 39
        if (empty($this->columnWidths)) {
426 35
            return '';
427
        }
428
429 4
        $content = '';
430 4
        foreach ($this->columnWidths as $styleIndex => $entry) {
431 4
            $numCols = $entry[1] - $entry[0] + 1;
432
            $content .= <<<EOD
433 4
<table:table-column table:default-cell-style-name='Default' table:style-name="co{$styleIndex}" table:number-columns-repeated="{$numCols}"/>
434
EOD;
435
        }
436
        // Note: This assumes the column widths are contiguous and default width is
437
        // only applied to columns after the last custom column with a custom width
438 4
        $content .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="default-column-style" table:number-columns-repeated="' . ($maxNumColumns - $entry[1]) . '"/>';
0 ignored issues
show
Bug introduced by
The variable $entry seems to be defined by a foreach iteration on line 430. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
439
440 4
        return $content;
441
    }
442
}
443