Completed
Pull Request — develop_3.0 (#434)
by Hura
04:17
created

WorksheetManager::addRow()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 45
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 6.0023

Importance

Changes 0
Metric Value
dl 0
loc 45
ccs 24
cts 25
cp 0.96
rs 8.439
c 0
b 0
f 0
cc 6
eloc 24
nc 10
nop 2
crap 6.0023
1
<?php
2
3
namespace Box\Spout\Writer\ODS\Manager;
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\Entity\Cell;
9
use Box\Spout\Writer\Common\Entity\Row;
10
use Box\Spout\Writer\Common\Entity\Style\Style;
11
use Box\Spout\Writer\Common\Entity\Worksheet;
12
use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface;
13
use Box\Spout\Writer\ODS\Helper\StyleHelper;
14
15
/**
16
 * Class WorksheetManager
17
 * ODS worksheet manager, providing the interfaces to work with ODS worksheets.
18
 *
19
 * @package Box\Spout\Writer\ODS\Manager
20
 */
21
class WorksheetManager implements WorksheetManagerInterface
22
{
23
    /** @var StyleHelper Helper to work with styles */
24
    private $styleHelper;
25
26
    /** @var \Box\Spout\Common\Escaper\ODS Strings escaper */
27
    private $stringsEscaper;
28
29
    /** @var StringHelper String helper */
30
    private $stringHelper;
31
32
    /**
33
     * WorksheetManager constructor.
34
     *
35
     * @param StyleHelper $styleHelper
36
     * @param \Box\Spout\Common\Escaper\ODS $stringsEscaper
37
     * @param StringHelper $stringHelper
38
     */
39 43
    public function __construct(
40
        StyleHelper $styleHelper,
41
        \Box\Spout\Common\Escaper\ODS $stringsEscaper,
42
        StringHelper $stringHelper)
43
    {
44 43
        $this->styleHelper = $styleHelper;
45 43
        $this->stringsEscaper = $stringsEscaper;
46 43
        $this->stringHelper = $stringHelper;
47 43
    }
48
49
    /**
50
     * Prepares the worksheet to accept data
51
     *
52
     * @param Worksheet $worksheet The worksheet to start
53
     * @return void
54
     * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
55
     */
56 43
    public function startSheet(Worksheet $worksheet)
57
    {
58 43
        $sheetFilePointer = fopen($worksheet->getFilePath(), 'w');
59 43
        $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
60
61 43
        $worksheet->setFilePointer($sheetFilePointer);
62 43
    }
63
64
    /**
65
     * Checks if the sheet has been sucessfully created. Throws an exception if not.
66
     *
67
     * @param bool|resource $sheetFilePointer Pointer to the sheet data file or FALSE if unable to open the file
68
     * @return void
69
     * @throws IOException If the sheet data file cannot be opened for writing
70
     */
71 43
    private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer)
72
    {
73 43
        if (!$sheetFilePointer) {
74
            throw new IOException('Unable to open sheet for writing.');
75
        }
76 43
    }
77
78
    /**
79
     * Returns the table XML root node as string.
80
     *
81
     * @param Worksheet $worksheet
82
     * @return string <table> node as string
83
     */
84 34
    public function getTableElementStartAsString(Worksheet $worksheet)
85
    {
86 34
        $externalSheet = $worksheet->getExternalSheet();
87 34
        $escapedSheetName = $this->stringsEscaper->escape($externalSheet->getName());
88 34
        $tableStyleName = 'ta' . ($externalSheet->getIndex() + 1);
89
90 34
        $tableElement  = '<table:table table:style-name="' . $tableStyleName . '" table:name="' . $escapedSheetName . '">';
91 34
        $tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co1" table:number-columns-repeated="' . $worksheet->getMaxNumColumns() . '"/>';
92
93 34
        return $tableElement;
94
    }
95
96
    /**
97
    /**
98
     * Adds a row to the worksheet.
99
     *
100
     * @param Worksheet $worksheet The worksheet to add the row to
101
     * @param Row $row The row to be added
102
     * @return void
103
     *
104
     * @throws IOException If the data cannot be written
105
     * @throws InvalidArgumentException If a cell value's type is not supported
106
     */
107 31
    public function addRow(Worksheet $worksheet, Row $row)
108
    {
109
110 31
        $cells = $row->getCells();
111 31
        $cellsCount = count($cells);
112
113 31
        $data = '<table:table-row table:style-name="ro1">';
114
115 31
        $currentCellIndex = 0;
116 31
        $nextCellIndex = 1;
117
118 31
        for ($i = 0; $i < $cellsCount; $i++) {
119
120
            /** @var Cell $cell */
121 31
            $cell = $row->getCells()[$currentCellIndex];
122
            /** @var Cell|null $nextCell */
123 31
            $nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null;
124
125 31
            if (null === $nextCell || $cell->getValue() !== $nextCell->getValue()) {
126
127
                // Apply styles - the row style is merged at this point
128 31
                $cell->applyStyle($row->getStyle());
129 31
                $this->styleHelper->applyExtraStylesIfNeeded($cell);
130 31
                $registeredStyle = $this->styleHelper->registerStyle($cell->getStyle());
0 ignored issues
show
Bug introduced by
It seems like $cell->getStyle() can be null; however, registerStyle() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
131 31
                $styleIndex = $registeredStyle->getId() + 1; // 1-based
132
133 31
                $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex);
134 31
                $data .= $this->getCellXML($cell, $styleIndex, $numTimesValueRepeated);
135 30
                $currentCellIndex = $nextCellIndex;
136
            }
137
138 30
            $nextCellIndex++;
139
        }
140
141 30
        $data .= '</table:table-row>';
142
143 30
        $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $data);
144 30
        if ($wasWriteSuccessful === false) {
145
            throw new IOException("Unable to write data in {$worksheet->getFilePath()}");
146
        }
147
148
        // only update the count if the write worked
149 30
        $lastWrittenRowIndex = $worksheet->getLastWrittenRowIndex();
150 30
        $worksheet->setLastWrittenRowIndex($lastWrittenRowIndex + 1);
151 30
    }
152
153
    /**
154
     * Returns the cell XML content, given its value.
155
     *
156
     * @param Cell $cell The cell to be written
157
     * @param int $styleIndex Index of the used style
158
     * @param int $numTimesValueRepeated Number of times the value is consecutively repeated
159
     * @return string The cell XML content
160
     * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported
161
     */
162 31
    protected function getCellXML(Cell $cell, $styleIndex, $numTimesValueRepeated)
163
    {
164 31
        $data = '<table:table-cell table:style-name="ce' . $styleIndex . '"';
165
166 31
        if ($numTimesValueRepeated !== 1) {
167 4
            $data .= ' table:number-columns-repeated="' . $numTimesValueRepeated . '"';
168
        }
169
170 31
        if ($cell->isString()) {
171 27
            $data .= ' office:value-type="string" calcext:value-type="string">';
172
173 27
            $cellValueLines = explode("\n", $cell->getValue());
174 27
            foreach ($cellValueLines as $cellValueLine) {
175 27
                $data .= '<text:p>' . $this->stringsEscaper->escape($cellValueLine) . '</text:p>';
176
            }
177
178 27
            $data .= '</table:table-cell>';
179 7
        } else if ($cell->isBoolean()) {
180 3
            $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $cell->getValue() . '">';
181 3
            $data .= '<text:p>' . $cell->getValue() . '</text:p>';
182 3
            $data .= '</table:table-cell>';
183 6
        } else if ($cell->isNumeric()) {
184 3
            $data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cell->getValue() . '">';
185 3
            $data .= '<text:p>' . $cell->getValue() . '</text:p>';
186 3
            $data .= '</table:table-cell>';
187 4
        } else if ($cell->isEmpty()) {
188 2
            $data .= '/>';
189
        } else {
190 2
            throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cell->getValue()));
191
        }
192
193 30
        return $data;
194
    }
195
196
    /**
197
     * Closes the worksheet
198
     *
199
     * @param Worksheet $worksheet
200
     * @return void
201
     */
202 34
    public function close(Worksheet $worksheet)
203
    {
204 34
        $worksheetFilePointer = $worksheet->getFilePointer();
205
206 34
        if (!is_resource($worksheetFilePointer)) {
207
            return;
208
        }
209
210 34
        fclose($worksheetFilePointer);
211
    }
212
}