Completed
Push — master ( 2d139c...e71e30 )
by Stefan
02:44
created

Sheet::getColumnWidths()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 5
Bugs 1 Features 3
Metric Value
c 5
b 1
f 3
dl 0
loc 12
ccs 9
cts 9
cp 1
rs 9.2
cc 4
eloc 7
nc 4
nop 0
crap 4
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 15
    public function __construct(CellBuilder $cellBuilder, SizeCalculator $sizeCalculator)
80
    {
81 15
        $this->cellBuilder = $cellBuilder;
82 15
        $this->sizeCalculator = $sizeCalculator;
83 15
    }
84
85
    /**
86
     * Enable cell autosizing (~30-100% performance hit!).
87
     */
88 6
    public function enableCellAutosizing()
89
    {
90 6
        $this->useCellAutosizing = true;
91 6
    }
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 2
    public function setColumnWidthLimits($minWidth = null, $maxWidth = null)
133
    {
134 2
        $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 2
        $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 2
    }
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 5
    public function getColumnWidths()
145
    {
146 5
        foreach ($this->columnWidths as $column => $width) {
147 5
            if ($width > $this->maxColumnWidth) {
148 1
                $this->columnWidths[$column] = $this->maxColumnWidth;
149 5
            } elseif ($width < $this->minColumnWidth) {
150 1
                $this->columnWidths[$column] = $this->minColumnWidth;
151 1
            }
152 5
        }
153
154 5
        return $this->columnWidths;
155
    }
156
157
    /**
158
     * Add single row and style to sheet.
159
     *
160
     * @param array $row
161
     * @param Style $style
162
     *
163
     * @return string
164
     */
165 5
    public function addRow(array $row, Style $style)
166
    {
167 5
        $columnCount = count($row);
168 5
        $this->updateMaxColumnCount($columnCount);
169
170 5
        $this->sizeCalculator->setFont($style->getFont());
171 5
        $cellXml = $this->getCellXml($row, $style);
172
173 5
        return $this->getRowXml($style, $columnCount, $cellXml);
174
    }
175
176
    /**
177
     * Track column count for dimensions xml (e.g. A1:K123).
178
     *
179
     * @param int $columnCount
180
     */
181 5
    private function updateMaxColumnCount($columnCount)
182
    {
183 5
        if ($this->maxColumnCount < $columnCount) {
184 5
            $this->maxColumnCount = $columnCount;
185 5
        }
186 5
    }
187
188
    /**
189
     * Build and return xml string for single row.
190
     *
191
     * @param Style  $style
192
     * @param int    $columnCount
193
     * @param string $cellXml
194
     * @return string
195
     */
196 5
    private function getRowXml(Style $style, $columnCount, $cellXml)
197
    {
198 5
        if ($style->getFont()->getSize() < 14) {
199 5
            return sprintf(RowXml::DEFAULT_XML, $this->rowIndex++, $columnCount, $cellXml);
200
        }
201
202 1
        return sprintf(RowXml::HEIGHT_XML, $this->rowIndex++, $columnCount,
203 1
            $this->sizeCalculator->getRowHeight(), $cellXml);
204
    }
205
206
    /**
207
     * Build and return xml string for single cell and update cell widths.
208
     *
209
     * @param array $row
210
     * @param Style $style
211
     * @return string
212
     */
213 5
    private function getCellXml(array $row, Style $style)
214
    {
215 5
        $cellXml = '';
216 5
        foreach (array_values($row) as $cellIndex => $cellValue) {
217 5
            $this->updateColumnWidths($cellValue, $cellIndex, $style);
218 5
            $cellXml .= $this->cellBuilder->build(
219 5
                $this->rowIndex, $cellIndex, $cellValue, $style->getId()
220 5
            );
221 5
        }
222
223 5
        return $cellXml;
224
    }
225
226
    /**
227
     * Track cell width for column width sizing if its enabled.
228
     *
229
     * @param mixed $value
230
     * @param int   $cellIndex
231
     * @param Style $style
232
     */
233 5
    private function updateColumnWidths($value, $cellIndex, Style $style)
234
    {
235 5
        if ($this->useCellAutosizing) {
236 4
            $cellWidth = $this->sizeCalculator->getCellWidth($value, $style->getFont());
237 4
            if (!isset($this->columnWidths[$cellIndex])
238 4
                || $this->columnWidths[$cellIndex] < $cellWidth
239 4
            ) {
240 4
                $this->columnWidths[$cellIndex] = $cellWidth;
241 4
            }
242 4
        }
243 5
    }
244
245
    /**
246
     * Return xml string for dimension.
247
     *
248
     * @return string
249
     */
250 1
    public function getDimensionXml()
251
    {
252 1
        return sprintf(SheetXml::DIMENSION_XML,
253 1
            $this->cellBuilder->getCellId($this->maxColumnCount - 1, $this->rowIndex - 1)
254 1
        );
255
    }
256
257
    /**
258
     * Return sheetViews xml containing the freeze pane.
259
     * <sheetViews> Currently leads to random excel crashes :-/
260
     *
261
     * @return string
262
     */
263 2
    public function getSheetViewsXml()
264
    {
265 2
        if (1 !== preg_match('~^[A-Z]+(\d+)$~', $this->freezePaneCellId, $m)) {
266 2
            return '';
267
        }
268
269 1
        return sprintf(SheetXml::SHEETVIEWS_XML, array_pop($m) - 1, $this->freezePaneCellId);
270
    }
271
}
272