Failed Conditions
Pull Request — develop_3.0 (#434)
by Hura
03:29
created

WorksheetManager::close()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2.0185
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\Worksheet;
11
use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface;
12
use Box\Spout\Writer\ODS\Manager\Style\StyleManager;
13
14
/**
15
 * Class WorksheetManager
16
 * ODS worksheet manager, providing the interfaces to work with ODS worksheets.
17
 *
18
 * @package Box\Spout\Writer\ODS\Manager
19
 */
20
class WorksheetManager implements WorksheetManagerInterface
21
{
22
    /** @var \Box\Spout\Common\Escaper\ODS Strings escaper */
23
    private $stringsEscaper;
24
25
    /** @var StringHelper String helper */
26
    private $stringHelper;
27
28
    /** @var StyleManager Manages styles */
29
    private $styleManager;
30
31
    /**
32
     * WorksheetManager constructor.
33
     * @param StyleManager $styleManager
34
     * @param \Box\Spout\Common\Escaper\ODS $stringsEscaper
35
     * @param StringHelper $stringHelper
36
     */
37 43
    public function __construct(
38
        StyleManager $styleManager,
39
        \Box\Spout\Common\Escaper\ODS $stringsEscaper,
40
        StringHelper $stringHelper)
41
    {
42 43
        $this->stringsEscaper = $stringsEscaper;
43 43
        $this->stringHelper = $stringHelper;
44 43
        $this->styleManager = $styleManager;
45 43
    }
46
47
    /**
48
     * Prepares the worksheet to accept data
49
     *
50
     * @param Worksheet $worksheet The worksheet to start
51
     * @return void
52
     * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
53
     */
54 43
    public function startSheet(Worksheet $worksheet)
55
    {
56 43
        $sheetFilePointer = fopen($worksheet->getFilePath(), 'w');
57 43
        $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
58
59 43
        $worksheet->setFilePointer($sheetFilePointer);
60 43
    }
61
62
    /**
63
     * Checks if the sheet has been sucessfully created. Throws an exception if not.
64
     *
65
     * @param bool|resource $sheetFilePointer Pointer to the sheet data file or FALSE if unable to open the file
66
     * @return void
67
     * @throws IOException If the sheet data file cannot be opened for writing
68
     */
69 43
    private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer)
70
    {
71 43
        if (!$sheetFilePointer) {
72
            throw new IOException('Unable to open sheet for writing.');
73
        }
74 43
    }
75
76
    /**
77
     * Returns the table XML root node as string.
78
     *
79
     * @param Worksheet $worksheet
80
     * @return string <table> node as string
81
     */
82 34
    public function getTableElementStartAsString(Worksheet $worksheet)
83
    {
84 34
        $externalSheet = $worksheet->getExternalSheet();
85 34
        $escapedSheetName = $this->stringsEscaper->escape($externalSheet->getName());
86 34
        $tableStyleName = 'ta' . ($externalSheet->getIndex() + 1);
87
88 34
        $tableElement  = '<table:table table:style-name="' . $tableStyleName . '" table:name="' . $escapedSheetName . '">';
89 34
        $tableElement .= '<table:table-column table:default-cell-style-name="ce1" table:style-name="co1" table:number-columns-repeated="' . $worksheet->getMaxNumColumns() . '"/>';
90
91 34
        return $tableElement;
92
    }
93
94
    /**
95
     * Adds a row to the worksheet.
96
     *
97
     * @param Worksheet $worksheet The worksheet to add the row to
98
     * @param Row $row The row to be added
99
     * @return void
100
     *
101
     * @throws IOException If the data cannot be written
102
     * @throws InvalidArgumentException If a cell value's type is not supported
103
     */
104 31
    public function addRow(Worksheet $worksheet, Row $row)
105
    {
106
107 31
        $cells = $row->getCells();
108 31
        $cellsCount = count($cells);
109
110 31
        $data = '<table:table-row table:style-name="ro1">';
111
112 31
        $currentCellIndex = 0;
113 31
        $nextCellIndex = 1;
114
115 31
        for ($i = 0; $i < $cellsCount; $i++) {
116
117
            /** @var Cell $cell */
118 31
            $cell = $cells[$currentCellIndex];
119
            /** @var Cell|null $nextCell */
120 31
            $nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null;
121
122 31
            if (null === $nextCell || $cell->getValue() !== $nextCell->getValue()) {
123
124
                // Apply styles - the row style is merged at this point
125 31
                $cell->applyStyle($row->getStyle());
126 31
                $this->styleManager->applyExtraStylesIfNeeded($cell);
127 31
                $registeredStyle = $this->styleManager->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...
128 31
                $styleIndex = $registeredStyle->getId() + 1; // 1-based
129
130 31
                $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex);
131 31
                $data .= $this->getCellXML($cell, $styleIndex, $numTimesValueRepeated);
132 30
                $currentCellIndex = $nextCellIndex;
133
            }
134
135 30
            $nextCellIndex++;
136
        }
137
138 30
        $data .= '</table:table-row>';
139
140 30
        $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $data);
141 30
        if ($wasWriteSuccessful === false) {
142
            throw new IOException("Unable to write data in {$worksheet->getFilePath()}");
143
        }
144
145
        // only update the count if the write worked
146 30
        $lastWrittenRowIndex = $worksheet->getLastWrittenRowIndex();
147 30
        $worksheet->setLastWrittenRowIndex($lastWrittenRowIndex + 1);
148 30
    }
149
150
    /**
151
     * Returns the cell XML content, given its value.
152
     *
153
     * @param Cell $cell The cell to be written
154
     * @param int $styleIndex Index of the used style
155
     * @param int $numTimesValueRepeated Number of times the value is consecutively repeated
156
     * @return string The cell XML content
157
     * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported
158
     */
159 31
    protected function getCellXML(Cell $cell, $styleIndex, $numTimesValueRepeated)
160
    {
161 31
        $data = '<table:table-cell table:style-name="ce' . $styleIndex . '"';
162
163 31
        if ($numTimesValueRepeated !== 1) {
164 4
            $data .= ' table:number-columns-repeated="' . $numTimesValueRepeated . '"';
165
        }
166
167 31
        if ($cell->isString()) {
168 27
            $data .= ' office:value-type="string" calcext:value-type="string">';
169
170 27
            $cellValueLines = explode("\n", $cell->getValue());
171 27
            foreach ($cellValueLines as $cellValueLine) {
172 27
                $data .= '<text:p>' . $this->stringsEscaper->escape($cellValueLine) . '</text:p>';
173
            }
174
175 27
            $data .= '</table:table-cell>';
176 7
        } else if ($cell->isBoolean()) {
177 3
            $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $cell->getValue() . '">';
178 3
            $data .= '<text:p>' . $cell->getValue() . '</text:p>';
179 3
            $data .= '</table:table-cell>';
180 6
        } else if ($cell->isNumeric()) {
181 3
            $data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cell->getValue() . '">';
182 3
            $data .= '<text:p>' . $cell->getValue() . '</text:p>';
183 3
            $data .= '</table:table-cell>';
184 4
        } else if ($cell->isEmpty()) {
185 2
            $data .= '/>';
186
        } else {
187 2
            throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cell->getValue()));
188
        }
189
190 30
        return $data;
191
    }
192
193
    /**
194
     * Closes the worksheet
195
     *
196
     * @param Worksheet $worksheet
197
     * @return void
198
     */
199 34
    public function close(Worksheet $worksheet)
200
    {
201 34
        $worksheetFilePointer = $worksheet->getFilePointer();
202
203 34
        if (!is_resource($worksheetFilePointer)) {
204
            return;
205
        }
206
207 34
        fclose($worksheetFilePointer);
208
    }
209
}