Completed
Push — master ( 4847fc...8f2a76 )
by Stefan
02:32
created

Sheet::getColumnWidths()   B

Complexity

Conditions 5
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 5.583

Importance

Changes 3
Bugs 1 Features 2
Metric Value
c 3
b 1
f 2
dl 0
loc 10
ccs 5
cts 7
cp 0.7143
rs 8.8571
cc 5
eloc 8
nc 1
nop 0
crap 5.583
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\Width\WidthCalculator;
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 WidthCalculator
24
     */
25
    private $widthCalculator;
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 array
62
     */
63
    private $minColumnWidth;
64
65
    /**
66
     * Holds maximum allowed column width.
67
     *
68
     * @var array
69
     */
70
    private $maxColumnWidth;
71
72
    /**
73
     * Sheet constructor.
74
     *
75
     * @param CellBuilder     $cellBuilder
76
     * @param WidthCalculator $widthCalculator
77
     */
78 13
    public function __construct(CellBuilder $cellBuilder, WidthCalculator $widthCalculator)
79
    {
80 13
        $this->cellBuilder = $cellBuilder;
81 13
        $this->widthCalculator = $widthCalculator;
82 13
    }
83
84
    /**
85
     * Enable cell autosizing (~30% performance hit!).
86
     */
87 5
    public function enableCellAutosizing()
88
    {
89 5
        $this->useCellAutosizing = true;
90 5
    }
91
92
    /**
93
     * Disable cell autosizing (default).
94
     */
95 2
    public function disableCellAutosizing()
96
    {
97 2
        $this->useCellAutosizing = false;
98 2
    }
99
100
    /**
101
     * @param int $cellId
102
     */
103 2
    public function setFreezePaneCellId($cellId)
104
    {
105 2
        $this->freezePaneCellId = $cellId;
106 2
    }
107
108
    /**
109
     * Set custom column widths with 0 representing the first column.
110
     *
111
     * @param array $columnWidths
112
     * @throws \InvalidArgumentException
113
     */
114 4
    public function setFixedColumnWidths(array $columnWidths)
115
    {
116 4
        if ($columnWidths !== array_filter($columnWidths, 'is_numeric')
117 4
            || array_keys($columnWidths) !== array_filter(array_keys($columnWidths), 'is_int')
118 4
        ) {
119 2
            throw new \InvalidArgumentException('Array must contain integer keys and numeric values only!');
120
        }
121
122 2
        $this->columnWidths = $columnWidths + $this->columnWidths;
123 2
    }
124
125
    /**
126
     * Set lower and/or upper limits for column widths.
127
     *
128
     * @param float|null $minWidth
129
     * @param float|null $maxWidth
130
     */
131
    public function setColumnWidthBoundries($minWidth = null, $maxWidth = null)
132
    {
133
        $this->minColumnWidth = $minWidth ?: null;
0 ignored issues
show
Documentation Bug introduced by
It seems like $minWidth ?: null of type double or null is incompatible with the declared type array of property $minColumnWidth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
134
        $this->maxColumnWidth = $maxWidth ?: null;
0 ignored issues
show
Documentation Bug introduced by
It seems like $maxWidth ?: null of type double or null is incompatible with the declared type array of property $maxColumnWidth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
135
    }
136
137
    /**
138
     * Return array containing all column widths, limited to min or max
139
     * column width, if one or both of them are set.
140
     *
141
     * @return array
142
     */
143
    public function getColumnWidths()
144
    {
145 4
        return array_map(function ($width) {
146 4
            if ($this->maxColumnWidth && $this->maxColumnWidth < $width) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->maxColumnWidth of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
147
                return $this->maxColumnWidth;
148 4
            } elseif ($this->minColumnWidth && $this->minColumnWidth > $width) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->minColumnWidth of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
149
                return $this->minColumnWidth;
150 4
            } return $width;
151 4
        }, $this->columnWidths);
152
    }
153
154
    /**
155
     * Return cellId for dimensions.
156
     *
157
     * @return string
158
     */
159 1
    public function getDimensionUpperBound()
160
    {
161 1
        return $this->cellBuilder->getCellId($this->maxColumnCount, $this->rowIndex - 1);
162
    }
163
164
    /**
165
     * Add single row and style to sheet.
166
     *
167
     * @param array $row
168
     * @param Style $style
169
     *
170
     * @return string
171
     */
172 4
    public function addRow(array $row, Style $style)
173
    {
174 4
        $columnCount = count($row);
175 4
        $this->updateMaxColumnCount($columnCount);
176
177 4
        $this->widthCalculator->setFont($style->getFont());
178 4
        $cellXml = $this->getCellXml($row, $style);
179
180 4
        if (!$this->useCellAutosizing || $style->getFont()->getSize() < 14) {
181 4
            return sprintf(RowXml::DEFAULT_XML, $this->rowIndex++, $columnCount, $cellXml);
182
        }
183
184 1
        return sprintf(RowXml::HEIGHT_XML, $this->rowIndex++, $columnCount,
185 1
            $style->getFont()->getSize() * 1.4, $cellXml);
186
    }
187
188
    /**
189
     * Track column count for dimensions xml (e.g. A1:K123).
190
     *
191
     * @param int $columnCount
192
     */
193 4
    private function updateMaxColumnCount($columnCount)
194
    {
195 4
        if ($this->maxColumnCount < $columnCount) {
196 4
            $this->maxColumnCount = $columnCount;
197 4
        }
198 4
    }
199
200
    /**
201
     * Get xml string for single cell and update cell widths.
202
     *
203
     * @param array $row
204
     * @param Style $style
205
     * @return string
206
     */
207 4
    private function getCellXml(array $row, Style $style)
208
    {
209 4
        $cellXml = '';
210 4
        foreach (array_values($row) as $cellIndex => $cellValue) {
211 4
            if (0 < strlen($cellValue)) {
212 4
                $this->updateColumnWidths($cellValue, $cellIndex, $style);
213 4
                $cellXml .= $this->cellBuilder->build($this->rowIndex, $cellIndex, $cellValue, $style->getId());
214 4
            }
215 4
        }
216
217 4
        return $cellXml;
218
    }
219
220
    /**
221
     * Track cell width for column width sizing if its enabled.
222
     *
223
     * @param mixed $value
224
     * @param int   $cellIndex
225
     * @param Style $style
226
     */
227 4
    private function updateColumnWidths($value, $cellIndex, Style $style)
228
    {
229 4
        if ($this->useCellAutosizing) {
230 3
            $cellWidth = $this->widthCalculator->getCellWidth($value, $style->getFont());
231 3
            if (!isset($this->columnWidths[$cellIndex])
232 3
                || $this->columnWidths[$cellIndex] < $cellWidth
233 3
            ) {
234 3
                $this->columnWidths[$cellIndex] = $cellWidth;
235 3
            }
236 3
        }
237 4
    }
238
239
    /**
240
     * Return freeze pane xml string for sheetView.
241
     *
242
     * @return string
243
     */
244 2
    public function getFreezePaneXml()
245
    {
246 2
        if (!$this->freezePaneCellId
247 2
            || 1 !== preg_match('~^[A-Z]+(\d+)$~', $this->freezePaneCellId, $m)
248 2
        ) {
249 2
            return '';
250
        }
251 1
        return sprintf(SheetXml::FREEZE_PANE_XML, array_pop($m) - 1, $this->freezePaneCellId);
252
    }
253
}
254