Completed
Pull Request — develop_3.0 (#434)
by Hura
03:59
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
     *
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
    /**
96
     * Adds a row to the worksheet.
97
     *
98
     * @param Worksheet $worksheet The worksheet to add the row to
99
     * @param Row $row The row to be added
100
     * @return void
101
     *
102
     * @throws IOException If the data cannot be written
103
     * @throws InvalidArgumentException If a cell value's type is not supported
104
     */
105 31
    public function addRow(Worksheet $worksheet, Row $row)
106
    {
107
108 31
        $cells = $row->getCells();
109 31
        $cellsCount = count($cells);
110
111 31
        $data = '<table:table-row table:style-name="ro1">';
112
113 31
        $currentCellIndex = 0;
114 31
        $nextCellIndex = 1;
115
116 31
        for ($i = 0; $i < $cellsCount; $i++) {
117
118
            /** @var Cell $cell */
119 31
            $cell = $row->getCells()[$currentCellIndex];
120
            /** @var Cell|null $nextCell */
121 31
            $nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null;
122
123 31
            if (null === $nextCell || $cell->getValue() !== $nextCell->getValue()) {
124
125
                // Apply styles - the row style is merged at this point
126 31
                $cell->applyStyle($row->getStyle());
127 31
                $this->styleManager->applyExtraStylesIfNeeded($cell);
128 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...
129 31
                $styleIndex = $registeredStyle->getId() + 1; // 1-based
130
131 31
                $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex);
132 31
                $data .= $this->getCellXML($cell, $styleIndex, $numTimesValueRepeated);
133 30
                $currentCellIndex = $nextCellIndex;
134
            }
135
136 30
            $nextCellIndex++;
137
        }
138
139 30
        $data .= '</table:table-row>';
140
141 30
        $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $data);
142 30
        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 30
        $lastWrittenRowIndex = $worksheet->getLastWrittenRowIndex();
148 30
        $worksheet->setLastWrittenRowIndex($lastWrittenRowIndex + 1);
149 30
    }
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 31
    protected function getCellXML(Cell $cell, $styleIndex, $numTimesValueRepeated)
161
    {
162 31
        $data = '<table:table-cell table:style-name="ce' . $styleIndex . '"';
163
164 31
        if ($numTimesValueRepeated !== 1) {
165 4
            $data .= ' table:number-columns-repeated="' . $numTimesValueRepeated . '"';
166
        }
167
168 31
        if ($cell->isString()) {
169 27
            $data .= ' office:value-type="string" calcext:value-type="string">';
170
171 27
            $cellValueLines = explode("\n", $cell->getValue());
172 27
            foreach ($cellValueLines as $cellValueLine) {
173 27
                $data .= '<text:p>' . $this->stringsEscaper->escape($cellValueLine) . '</text:p>';
174
            }
175
176 27
            $data .= '</table:table-cell>';
177 7
        } 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 6
        } 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 4
        } else if ($cell->isEmpty()) {
186 2
            $data .= '/>';
187
        } else {
188 2
            throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cell->getValue()));
189
        }
190
191 30
        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
}