Completed
Push — master ( 84ee67...48a23c )
by Stefan
02:40
created

Sheet::getRowXml()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
cc 2
eloc 5
nc 2
nop 3
crap 2
1
<?php
2
3
namespace OneSheet;
4
5
use OneSheet\Xml\RowXml;
6
use OneSheet\Style\Style;
7
use OneSheet\Xml\SheetXml;
8
use OneSheet\Size\SizeCalculator;
9
10
/**
11
 * Class Sheet
12
 *
13
 * @package OneSheet
14
 */
15
class Sheet
16
{
17
    /**
18
     * @var CellBuilder
19
     */
20
    private $cellBuilder;
21
22
    /**
23
     * @var SizeCalculator
24
     */
25
    private $sizeCalculator;
26
27
    /**
28
     * @var bool
29
     */
30
    private $useCellAutosizing = false;
31
32
    /**
33
     * @var int
34
     */
35
    private $freezePaneCellId;
36
37
    /**
38
     * Track next row index.
39
     *
40
     * @var int
41
     */
42
    private $rowIndex = 1;
43
44
    /**
45
     * Holds width/column count of the widest row.
46
     *
47
     * @var int
48
     */
49
    private $maxColumnCount;
50
51
    /**
52
     * Holds widths of the widest cells for column sizing.
53
     *
54
     * @var array
55
     */
56
    private $columnWidths = array();
57
58
    /**
59
     * Holds minimum allowed column width.
60
     *
61
     * @var float|int
62
     */
63
    private $minColumnWidth = 0;
64
65
    /**
66
     * Holds maximum allowed column width. 254.86 appears
67
     * to be the default maximum width.
68
     *
69
     * @var float|int
70
     */
71
    private $maxColumnWidth = 254.86;
72
73
    /**
74
     * Sheet constructor.
75
     *
76
     * @param CellBuilder    $cellBuilder
77
     * @param SizeCalculator $sizeCalculator
78
     */
79 14
    public function __construct(CellBuilder $cellBuilder, SizeCalculator $sizeCalculator)
80
    {
81 14
        $this->cellBuilder = $cellBuilder;
82 14
        $this->sizeCalculator = $sizeCalculator;
83 14
    }
84
85
    /**
86
     * Enable cell autosizing (~30-100% performance hit!).
87
     */
88 5
    public function enableCellAutosizing()
89
    {
90 5
        $this->useCellAutosizing = true;
91 5
    }
92
93
    /**
94
     * Disable cell autosizing (default).
95
     */
96 2
    public function disableCellAutosizing()
97
    {
98 2
        $this->useCellAutosizing = false;
99 2
    }
100
101
    /**
102
     * @param int $cellId
103
     */
104 2
    public function setFreezePaneCellId($cellId)
105
    {
106 2
        $this->freezePaneCellId = $cellId;
107 2
    }
108
109
    /**
110
     * Set custom column widths with 0 representing the first column.
111
     *
112
     * @param array $columnWidths
113
     * @throws \InvalidArgumentException
114
     */
115 4
    public function setFixedColumnWidths(array $columnWidths)
116
    {
117 4
        if ($columnWidths !== array_filter($columnWidths, 'is_numeric')
118 4
            || array_keys($columnWidths) !== array_filter(array_keys($columnWidths), 'is_int')
119 4
        ) {
120 2
            throw new \InvalidArgumentException('Array must contain integer keys and numeric values only!');
121
        }
122
123 2
        $this->columnWidths = $columnWidths + $this->columnWidths;
124 2
    }
125
126
    /**
127
     * Set lower and/or upper limits for column widths.
128
     *
129
     * @param float|null $minWidth
130
     * @param float|null $maxWidth
131
     */
132 1
    public function setColumnWidthLimits($minWidth = null, $maxWidth = null)
133
    {
134 1
        $this->minColumnWidth = is_numeric($minWidth) && $minWidth >= 0 ? $minWidth : 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like is_numeric($minWidth) &&...th >= 0 ? $minWidth : 0 can also be of type string. However, the property $minColumnWidth is declared as type double|integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
135 1
        $this->maxColumnWidth = is_numeric($maxWidth) && $maxWidth < 255.86 ? $maxWidth : 255.86;
0 ignored issues
show
Documentation Bug introduced by
It seems like is_numeric($maxWidth) &&...86 ? $maxWidth : 255.86 can also be of type string. However, the property $maxColumnWidth is declared as type double|integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
136 1
    }
137
138
    /**
139
     * Return array containing all column widths, limited to min or max
140
     * column width, if one or both of them are set.
141
     *
142
     * @return array
143
     */
144 4
    public function getColumnWidths()
145
    {
146 4
        foreach ($this->columnWidths as $column => $width) {
147 4
            if ($this->maxColumnWidth && $width > $this->maxColumnWidth) {
148
                $this->columnWidths[$column] = $this->maxColumnWidth;
149 4
            } elseif ($this->minColumnWidth && $width < $this->minColumnWidth) {
150
                $this->columnWidths[$column] = $this->minColumnWidth;
151
            }
152 4
        }
153
154 4
        return $this->columnWidths;
155
    }
156
157
    /**
158
     * Return cellId for dimensions.
159
     *
160
     * @return string
161
     */
162 1
    public function getDimensionUpperBound()
163
    {
164 1
        return $this->cellBuilder->getCellId($this->maxColumnCount, $this->rowIndex - 1);
165
    }
166
167
    /**
168
     * Add single row and style to sheet.
169
     *
170
     * @param array $row
171
     * @param Style $style
172
     *
173
     * @return string
174
     */
175 4
    public function addRow(array $row, Style $style)
176
    {
177 4
        $columnCount = count($row);
178 4
        $this->updateMaxColumnCount($columnCount);
179
180 4
        $this->sizeCalculator->setFont($style->getFont());
181 4
        $cellXml = $this->getCellXml($row, $style);
182
183 4
        return $this->getRowXml($style, $columnCount, $cellXml);
184
    }
185
186
    /**
187
     * Track column count for dimensions xml (e.g. A1:K123).
188
     *
189
     * @param int $columnCount
190
     */
191 4
    private function updateMaxColumnCount($columnCount)
192
    {
193 4
        if ($this->maxColumnCount < $columnCount) {
194 4
            $this->maxColumnCount = $columnCount;
195 4
        }
196 4
    }
197
198
    /**
199
     * Build and return xml string for single row.
200
     *
201
     * @param Style  $style
202
     * @param int    $columnCount
203
     * @param string $cellXml
204
     * @return string
205
     */
206 4
    private function getRowXml(Style $style, $columnCount, $cellXml)
207
    {
208 4
        if ($style->getFont()->getSize() < 14) {
209 4
            return sprintf(RowXml::DEFAULT_XML, $this->rowIndex++, $columnCount, $cellXml);
210
        }
211
212 1
        return sprintf(RowXml::HEIGHT_XML, $this->rowIndex++, $columnCount,
213 1
            $this->sizeCalculator->getRowHeight(), $cellXml);
214
    }
215
216
    /**
217
     * Build and return xml string for single cell and update cell widths.
218
     *
219
     * @param array $row
220
     * @param Style $style
221
     * @return string
222
     */
223 4
    private function getCellXml(array $row, Style $style)
224
    {
225 4
        $cellXml = '';
226 4
        foreach (array_values($row) as $cellIndex => $cellValue) {
227 4
            if (0 < strlen($cellValue)) {
228 4
                $this->updateColumnWidths($cellValue, $cellIndex, $style);
229 4
                $cellXml .= $this->cellBuilder->build(
230 4
                    $this->rowIndex, $cellIndex, $cellValue, $style->getId()
231 4
                );
232 4
            }
233 4
        }
234
235 4
        return $cellXml;
236
    }
237
238
    /**
239
     * Track cell width for column width sizing if its enabled.
240
     *
241
     * @param mixed $value
242
     * @param int   $cellIndex
243
     * @param Style $style
244
     */
245 4
    private function updateColumnWidths($value, $cellIndex, Style $style)
246
    {
247 4
        if ($this->useCellAutosizing) {
248 3
            $cellWidth = $this->sizeCalculator->getCellWidth($value, $style->getFont());
249 3
            if (!isset($this->columnWidths[$cellIndex])
250 3
                || $this->columnWidths[$cellIndex] < $cellWidth
251 3
            ) {
252 3
                $this->columnWidths[$cellIndex] = $cellWidth;
253 3
            }
254 3
        }
255 4
    }
256
257
    /**
258
     * Return freeze pane xml string for sheetView.
259
     *
260
     * @return string
261
     */
262 2
    public function getFreezePaneXml()
263
    {
264 2
        if (!$this->freezePaneCellId
265 2
            || 1 !== preg_match('~^[A-Z]+(\d+)$~', $this->freezePaneCellId, $m)
266 2
        ) {
267 2
            return '';
268
        }
269 1
        return sprintf(SheetXml::FREEZE_PANE_XML, array_pop($m) - 1, $this->freezePaneCellId);
270
    }
271
}
272