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