Completed
Pull Request — master (#715)
by
unknown
01:52 queued 19s
created

StyleManager::getTextPropertiesSectionContent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.9332
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 40
    public function getStylesXMLFileContent($numWorksheets)
29
    {
30
        $content = <<<'EOD'
31 40
<?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 40
        $content .= $this->getFontFaceSectionContent();
36 40
        $content .= $this->getStylesSectionContent();
37 40
        $content .= $this->getAutomaticStylesSectionContent($numWorksheets);
38 40
        $content .= $this->getMasterStylesSectionContent($numWorksheets);
39
40
        $content .= <<<'EOD'
41 40
</office:document-styles>
42
EOD;
43
44 40
        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 40
    protected function getFontFaceSectionContent()
53
    {
54 40
        $content = '<office:font-face-decls>';
55 40
        foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
56 40
            $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>';
57
        }
58 40
        $content .= '</office:font-face-decls>';
59
60 40
        return $content;
61
    }
62
63
    /**
64
     * Returns the content of the "<office:styles>" section, inside "styles.xml" file.
65
     *
66
     * @return string
67
     */
68 40
    protected function getStylesSectionContent()
69
    {
70 40
        $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 40
        <style:text-properties fo:color="#{$defaultStyle->getFontColor()}"
80 40
                               fo:font-size="{$defaultStyle->getFontSize()}pt" style:font-size-asian="{$defaultStyle->getFontSize()}pt" style:font-size-complex="{$defaultStyle->getFontSize()}pt"
81 40
                               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 40
    protected function getAutomaticStylesSectionContent($numWorksheets)
94
    {
95 40
        $content = '<office:automatic-styles>';
96
97 40
        for ($i = 1; $i <= $numWorksheets; $i++) {
98
            $content .= <<<EOD
99 40
<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 40
        $content .= '</office:automatic-styles>';
108
109 40
        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 40
    protected function getMasterStylesSectionContent($numWorksheets)
119
    {
120 40
        $content = '<office:master-styles>';
121
122 40
        for ($i = 1; $i <= $numWorksheets; $i++) {
123
            $content .= <<<EOD
124 40
<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 40
        $content .= '</office:master-styles>';
134
135 40
        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 40
    public function getContentXmlFontFaceSectionContent()
144
    {
145 40
        $content = '<office:font-face-decls>';
146 40
        foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
147 40
            $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>';
148
        }
149 40
        $content .= '</office:font-face-decls>';
150
151 40
        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 40
    public function getContentXmlAutomaticStylesSectionContent($worksheets)
161
    {
162 40
        $content = '<office:automatic-styles>';
163
164 40
        foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
165 40
            $content .= $this->getStyleSectionContent($style);
166
        }
167
168 40
        $useOptimalRowHeight = empty($this->defaultRowHeight) ? 'true' : 'false';
169 40
        $defaultRowHeight = empty($this->defaultRowHeight) ? '15pt' : "{$this->defaultRowHeight}pt";
170 40
        $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 40
    <style:table-column-properties fo:break-before="auto" {$defaultColumnWidth}/>
175
</style:style>
176
<style:style style:family="table-row" style:name="ro1">
177 40
    <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 40
        foreach ($worksheets as $worksheet) {
182 40
            $worksheetId = $worksheet->getId();
183 40
            $isSheetVisible = $worksheet->getExternalSheet()->isVisible() ? 'true' : 'false';
184
185
            $content .= <<<EOD
186 40
<style:style style:family="table" style:master-page-name="mp$worksheetId" style:name="ta$worksheetId">
187 40
    <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 1
            return ($a[0] < $b[0]) ? -1 : 1;
198 40
        });
199 40
        $content .= $this->getTableColumnStylesXMLContent();
200
201 40
        $content .= '</office:automatic-styles>';
202
203 40
        return $content;
204
    }
205
206
    /**
207
     * Returns the contents of the "<style:style>" section, inside "<office:automatic-styles>" section
208
     *
209
     * @param \Box\Spout\Common\Entity\Style\Style $style
210
     * @return string
211
     */
212 40
    protected function getStyleSectionContent($style)
213
    {
214 40
        $styleIndex = $style->getId() + 1; // 1-based
215
216 40
        $content = '<style:style style:data-style-name="N0" style:family="table-cell" style:name="ce' . $styleIndex . '" style:parent-style-name="Default">';
217
218 40
        $content .= $this->getTextPropertiesSectionContent($style);
219 40
        $content .= $this->getParagraphPropertiesSectionContent($style);
220 40
        $content .= $this->getTableCellPropertiesSectionContent($style);
221
222 40
        $content .= '</style:style>';
223
224 40
        return $content;
225
    }
226
227
    /**
228
     * Returns the contents of the "<style:text-properties>" section, inside "<style:style>" section
229
     *
230
     * @param \Box\Spout\Common\Entity\Style\Style $style
231
     * @return string
232
     */
233 40
    private function getTextPropertiesSectionContent($style)
234
    {
235 40
        if (!$style->shouldApplyFont()) {
236 39
            return '';
237
        }
238
239
        return '<style:text-properties '
240 5
            . $this->getFontSectionContent($style)
241 5
            . '/>';
242
    }
243
244
    /**
245
     * Returns the contents of the fonts definition section, inside "<style:text-properties>" section
246
     *
247
     * @param \Box\Spout\Common\Entity\Style\Style $style
248
     *
249
     * @return string
250
     */
251 5
    private function getFontSectionContent($style)
252
    {
253 5
        $defaultStyle = $this->getDefaultStyle();
254 5
        $content = '';
255
256 5
        $fontColor = $style->getFontColor();
257 5
        if ($fontColor !== $defaultStyle->getFontColor()) {
258 1
            $content .= ' fo:color="#' . $fontColor . '"';
259
        }
260
261 5
        $fontName = $style->getFontName();
262 5
        if ($fontName !== $defaultStyle->getFontName()) {
263 1
            $content .= ' style:font-name="' . $fontName . '" style:font-name-asian="' . $fontName . '" style:font-name-complex="' . $fontName . '"';
264
        }
265
266 5
        $fontSize = $style->getFontSize();
267 5
        if ($fontSize !== $defaultStyle->getFontSize()) {
268 2
            $content .= ' fo:font-size="' . $fontSize . 'pt" style:font-size-asian="' . $fontSize . 'pt" style:font-size-complex="' . $fontSize . 'pt"';
269
        }
270
271 5
        if ($style->isFontBold()) {
272 4
            $content .= ' fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"';
273
        }
274 5
        if ($style->isFontItalic()) {
275 1
            $content .= ' fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"';
276
        }
277 5
        if ($style->isFontUnderline()) {
278 2
            $content .= ' style:text-underline-style="solid" style:text-underline-type="single"';
279
        }
280 5
        if ($style->isFontStrikethrough()) {
281 1
            $content .= ' style:text-line-through-style="solid"';
282
        }
283
284 5
        return $content;
285
    }
286
287
    /**
288
     * Returns the contents of the "<style:paragraph-properties>" section, inside "<style:style>" section
289
     *
290
     * @param \Box\Spout\Common\Entity\Style\Style $style
291
     *
292
     * @return string
293
     */
294 40
    private function getParagraphPropertiesSectionContent($style)
295
    {
296 40
        if (!$style->shouldApplyCellAlignment()) {
297 40
            return '';
298
        }
299
300
        return '<style:paragraph-properties '
301 1
            . $this->getCellAlignmentSectionContent($style)
302 1
            . '/>';
303
    }
304
305
    /**
306
     * Returns the contents of the cell alignment definition for the "<style:paragraph-properties>" section
307
     *
308
     * @param \Box\Spout\Common\Entity\Style\Style $style
309
     *
310
     * @return string
311
     */
312 1
    private function getCellAlignmentSectionContent($style)
313
    {
314 1
        return \sprintf(
315 1
            ' fo:text-align="%s" ',
316 1
            $this->transformCellAlignment($style->getCellAlignment())
317
        );
318
    }
319
320
    /**
321
     * Even though "left" and "right" alignments are part of the spec, and interpreted
322
     * respectively as "start" and "end", using the recommended values increase compatibility
323
     * with software that will read the created ODS file.
324
     *
325
     * @param string $cellAlignment
326
     *
327
     * @return string
328
     */
329 1
    private function transformCellAlignment($cellAlignment)
330
    {
331
        switch ($cellAlignment) {
332 1
            case CellAlignment::LEFT:
333
                return 'start';
334 1
            case CellAlignment::RIGHT:
335 1
                return 'end';
336
            default:
337
                return $cellAlignment;
338
        }
339
    }
340
341
    /**
342
     * Returns the contents of the "<style:table-cell-properties>" section, inside "<style:style>" section
343
     *
344
     * @param \Box\Spout\Common\Entity\Style\Style $style
345
     * @return string
346
     */
347 40
    private function getTableCellPropertiesSectionContent($style)
348
    {
349 40
        $content = '<style:table-cell-properties ';
350
351 40
        if ($style->shouldWrapText()) {
352 3
            $content .= $this->getWrapTextXMLContent();
353
        }
354
355 40
        if ($style->shouldApplyBorder()) {
356 1
            $content .= $this->getBorderXMLContent($style);
357
        }
358
359 40
        if ($style->shouldApplyBackgroundColor()) {
360 2
            $content .= $this->getBackgroundColorXMLContent($style);
361
        }
362
363 40
        $content .= '/>';
364
365 40
        return $content;
366
    }
367
368
    /**
369
     * Returns the contents of the wrap text definition for the "<style:table-cell-properties>" section
370
     *
371
     * @return string
372
     */
373 3
    private function getWrapTextXMLContent()
374
    {
375 3
        return ' fo:wrap-option="wrap" style:vertical-align="automatic" ';
376
    }
377
378
    /**
379
     * Returns the contents of the borders definition for the "<style:table-cell-properties>" section
380
     *
381
     * @param \Box\Spout\Common\Entity\Style\Style $style
382
     * @return string
383
     */
384 1
    private function getBorderXMLContent($style)
385
    {
386
        $borders = \array_map(function (BorderPart $borderPart) {
387 1
            return BorderHelper::serializeBorderPart($borderPart);
388 1
        }, $style->getBorder()->getParts());
389
390 1
        return \sprintf(' %s ', \implode(' ', $borders));
391
    }
392
393
    /**
394
     * Returns the contents of the background color definition for the "<style:table-cell-properties>" section
395
     *
396
     * @param \Box\Spout\Common\Entity\Style\Style $style
397
     * @return string
398
     */
399 2
    private function getBackgroundColorXMLContent($style)
400
    {
401 2
        return \sprintf(' fo:background-color="#%s" ', $style->getBackgroundColor());
402
    }
403
404 40
    public function getTableColumnStylesXMLContent() : string
405
    {
406 40
        if (empty($this->columnWidths)) {
407 36
            return '';
408
        }
409
410 4
        $content = '';
411 4
        foreach ($this->columnWidths as $styleIndex => $entry) {
412
            $content .= <<<EOD
413 4
<style:style style:family="table-column" style:name="co{$styleIndex}">
414 4
    <style:table-column-properties fo:break-before="auto" style:use-optimal-column-width="false" style:column-width="{$entry[2]}pt"/>
415
</style:style>
416
EOD;
417
        }
418 4
        return $content;
419
    }
420
421 40
    public function getStyledTableColumnXMLContent(int $maxNumColumns) : string
422
    {
423 40
        if (empty($this->columnWidths)) {
424 36
            return '';
425
        }
426
427 4
        $content = '';
428 4
        foreach ($this->columnWidths as $styleIndex => $entry) {
429 4
            $numCols = $entry[1] - $entry[0] + 1;
430
            $content .= <<<EOD
431 4
<table:table-column table:default-cell-style-name='Default' table:style-name="co{$styleIndex}" table:number-columns-repeated="{$numCols}"/>
432
EOD;
433
        }
434
        // Note: This assumes the column widths are contiguous and default width is
435
        // only applied to columns after the last custom column with a custom width
436 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 428. 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...
437 4
        return $content;
438
    }
439
}
440