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

throwIfSheetFilePointerIsNotAvailable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 4
cp 0.75
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
crap 2.0625
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 41
    public function __construct(
38
        StyleManager $styleManager,
39
        \Box\Spout\Common\Escaper\ODS $stringsEscaper,
40
        StringHelper $stringHelper)
41
    {
42 41
        $this->stringsEscaper = $stringsEscaper;
43 41
        $this->stringHelper = $stringHelper;
44 41
        $this->styleManager = $styleManager;
45 41
    }
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 41
    public function startSheet(Worksheet $worksheet)
55
    {
56 41
        $sheetFilePointer = fopen($worksheet->getFilePath(), 'w');
57 41
        $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
58
59 41
        $worksheet->setFilePointer($sheetFilePointer);
60 41
    }
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 41
    private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer)
70
    {
71 41
        if (!$sheetFilePointer) {
72
            throw new IOException('Unable to open sheet for writing.');
73
        }
74 41
    }
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 30
    public function addRow(Worksheet $worksheet, Row $row)
105
    {
106
107 30
        $cells = $row->getCells();
108 30
        $cellsCount = count($cells);
109
110 30
        $data = '<table:table-row table:style-name="ro1">';
111
112 30
        $currentCellIndex = 0;
113 30
        $nextCellIndex = 1;
114
115 30
        for ($i = 0; $i < $cellsCount; $i++) {
116
117
            /** @var Cell $cell */
118 30
            $cell = $cells[$currentCellIndex];
119
            /** @var Cell|null $nextCell */
120 30
            $nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null;
121
122
            // @TODO refactoring: move this to its own method
123 30
            if (null === $nextCell || $cell->getValue() !== $nextCell->getValue()) {
124
125
                // Apply styles - the row style is merged at this point
126 30
                $cell->applyStyle($row->getStyle());
127 30
                $this->styleManager->applyExtraStylesIfNeeded($cell);
128 30
                $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...
129 30
                $styleIndex = $registeredStyle->getId() + 1; // 1-based
130
131 30
                $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex);
132 30
                $data .= $this->getCellXML($cell, $styleIndex, $numTimesValueRepeated);
133 29
                $currentCellIndex = $nextCellIndex;
134
            }
135
136 29
            $nextCellIndex++;
137
        }
138
139 29
        $data .= '</table:table-row>';
140
141 29
        $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $data);
142 29
        if ($wasWriteSuccessful === false) {
143
            throw new IOException("Unable to write data in {$worksheet->getFilePath()}");
144
        }
145
146
        // only update the count if the write worked
147 29
        $lastWrittenRowIndex = $worksheet->getLastWrittenRowIndex();
148 29
        $worksheet->setLastWrittenRowIndex($lastWrittenRowIndex + 1);
149 29
    }
150
151
    /**
152
     * Returns the cell XML content, given its value.
153
     *
154
     * @param Cell $cell The cell to be written
155
     * @param int $styleIndex Index of the used style
156
     * @param int $numTimesValueRepeated Number of times the value is consecutively repeated
157
     * @return string The cell XML content
158
     * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported
159
     */
160 30
    protected function getCellXML(Cell $cell, $styleIndex, $numTimesValueRepeated)
161
    {
162 30
        $data = '<table:table-cell table:style-name="ce' . $styleIndex . '"';
163
164 30
        if ($numTimesValueRepeated !== 1) {
165 4
            $data .= ' table:number-columns-repeated="' . $numTimesValueRepeated . '"';
166
        }
167
168 30
        if ($cell->isString()) {
169 26
            $data .= ' office:value-type="string" calcext:value-type="string">';
170
171 26
            $cellValueLines = explode("\n", $cell->getValue());
172 26
            foreach ($cellValueLines as $cellValueLine) {
173 26
                $data .= '<text:p>' . $this->stringsEscaper->escape($cellValueLine) . '</text:p>';
174
            }
175
176 26
            $data .= '</table:table-cell>';
177 6
        } else if ($cell->isBoolean()) {
178 3
            $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $cell->getValue() . '">';
179 3
            $data .= '<text:p>' . $cell->getValue() . '</text:p>';
180 3
            $data .= '</table:table-cell>';
181 5
        } else if ($cell->isNumeric()) {
182 3
            $data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cell->getValue() . '">';
183 3
            $data .= '<text:p>' . $cell->getValue() . '</text:p>';
184 3
            $data .= '</table:table-cell>';
185 3
        } else if ($cell->isEmpty()) {
186 2
            $data .= '/>';
187
        } else {
188 1
            throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cell->getValue()));
189
        }
190
191 29
        return $data;
192
    }
193
194
    /**
195
     * Closes the worksheet
196
     *
197
     * @param Worksheet $worksheet
198
     * @return void
199
     */
200 34
    public function close(Worksheet $worksheet)
201
    {
202 34
        $worksheetFilePointer = $worksheet->getFilePointer();
203
204 34
        if (!is_resource($worksheetFilePointer)) {
205
            return;
206
        }
207
208 34
        fclose($worksheetFilePointer);
209
    }
210
}