Passed
Push — master ( 3e93d4...2d1f4e )
by
unknown
24:41 queued 16:58
created

DataSeriesValues::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 24
ccs 14
cts 14
cp 1
rs 9.8333
c 0
b 0
f 0
cc 3
nc 4
nop 8
crap 3

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Chart;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
6
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
7
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
8
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
9
10
class DataSeriesValues extends Properties
11
{
12
    const DATASERIES_TYPE_STRING = 'String';
13
    const DATASERIES_TYPE_NUMBER = 'Number';
14
15
    private const DATA_TYPE_VALUES = [
16
        self::DATASERIES_TYPE_STRING,
17
        self::DATASERIES_TYPE_NUMBER,
18
    ];
19
20
    /**
21
     * Series Data Type.
22
     */
23
    private string $dataType;
24
25
    /**
26
     * Series Data Source.
27
     */
28
    private ?string $dataSource;
29
30
    /**
31
     * Format Code.
32
     */
33
    private ?string $formatCode;
34
35
    /**
36
     * Series Point Marker.
37
     */
38
    private ?string $pointMarker;
39
40
    private ChartColor $markerFillColor;
41
42
    private ChartColor $markerBorderColor;
43
44
    /**
45
     * Series Point Size.
46
     */
47
    private int $pointSize = 3;
48
49
    /**
50
     * Point Count (The number of datapoints in the dataseries).
51
     */
52
    private int $pointCount;
53
54
    /**
55
     * Data Values.
56
     *
57
     * @var null|mixed[]
58
     */
59
    private ?array $dataValues;
60
61
    /**
62
     * Fill color (can be array with colors if dataseries have custom colors).
63
     *
64
     * @var null|ChartColor|ChartColor[]
65
     */
66
    private $fillColor;
67
68
    private bool $scatterLines = true;
69
70
    private bool $bubble3D = false;
71
72
    private ?Layout $labelLayout = null;
73
74
    /** @var TrendLine[] */
75
    private array $trendLines = [];
76
77
    /**
78
     * Create a new DataSeriesValues object.
79
     *
80
     * @param null|mixed[] $dataValues
81
     * @param null|ChartColor|ChartColor[]|string|string[] $fillColor
82
     */
83 118
    public function __construct(
84
        string $dataType = self::DATASERIES_TYPE_NUMBER,
85
        ?string $dataSource = null,
86
        ?string $formatCode = null,
87
        int $pointCount = 0,
88
        ?array $dataValues = [],
89
        ?string $marker = null,
90
        null|ChartColor|array|string $fillColor = null,
91
        int|string $pointSize = 3
92
    ) {
93 118
        parent::__construct();
94 118
        $this->markerFillColor = new ChartColor();
95 118
        $this->markerBorderColor = new ChartColor();
96 118
        $this->setDataType($dataType);
97 118
        $this->dataSource = $dataSource;
98 118
        $this->formatCode = $formatCode;
99 118
        $this->pointCount = $pointCount;
100 118
        $this->dataValues = $dataValues;
101 118
        $this->pointMarker = $marker;
102 118
        if ($fillColor !== null) {
103 27
            $this->setFillColor($fillColor);
104
        }
105 118
        if (is_numeric($pointSize)) {
106 115
            $this->pointSize = (int) $pointSize;
107
        }
108
    }
109
110
    /**
111
     * Get Series Data Type.
112
     */
113 85
    public function getDataType(): string
114
    {
115 85
        return $this->dataType;
116
    }
117
118
    /**
119
     * Set Series Data Type.
120
     *
121
     * @param string $dataType Datatype of this data series
122
     *                                Typical values are:
123
     *                                    DataSeriesValues::DATASERIES_TYPE_STRING
124
     *                                        Normally used for axis point values
125
     *                                    DataSeriesValues::DATASERIES_TYPE_NUMBER
126
     *                                        Normally used for chart data values
127
     *
128
     * @return $this
129
     */
130 118
    public function setDataType(string $dataType): static
131
    {
132 118
        if (!in_array($dataType, self::DATA_TYPE_VALUES)) {
133 1
            throw new Exception('Invalid datatype for chart data series values');
134
        }
135 118
        $this->dataType = $dataType;
136
137 118
        return $this;
138
    }
139
140
    /**
141
     * Get Series Data Source (formula).
142
     */
143 93
    public function getDataSource(): ?string
144
    {
145 93
        return $this->dataSource;
146
    }
147
148
    /**
149
     * Set Series Data Source (formula).
150
     *
151
     * @return $this
152
     */
153 1
    public function setDataSource(?string $dataSource): static
154
    {
155 1
        $this->dataSource = $dataSource;
156
157 1
        return $this;
158
    }
159
160
    /**
161
     * Get Point Marker.
162
     */
163 95
    public function getPointMarker(): ?string
164
    {
165 95
        return $this->pointMarker;
166
    }
167
168
    /**
169
     * Set Point Marker.
170
     *
171
     * @return $this
172
     */
173 4
    public function setPointMarker(string $marker): static
174
    {
175 4
        $this->pointMarker = $marker;
176
177 4
        return $this;
178
    }
179
180 96
    public function getMarkerFillColor(): ChartColor
181
    {
182 96
        return $this->markerFillColor;
183
    }
184
185 96
    public function getMarkerBorderColor(): ChartColor
186
    {
187 96
        return $this->markerBorderColor;
188
    }
189
190
    /**
191
     * Get Point Size.
192
     */
193 27
    public function getPointSize(): int
194
    {
195 27
        return $this->pointSize;
196
    }
197
198
    /**
199
     * Set Point Size.
200
     *
201
     * @return $this
202
     */
203 4
    public function setPointSize(int $size = 3): static
204
    {
205 4
        $this->pointSize = $size;
206
207 4
        return $this;
208
    }
209
210
    /**
211
     * Get Series Format Code.
212
     */
213 88
    public function getFormatCode(): ?string
214
    {
215 88
        return $this->formatCode;
216
    }
217
218
    /**
219
     * Set Series Format Code.
220
     *
221
     * @return $this
222
     */
223 67
    public function setFormatCode(string $formatCode): static
224
    {
225 67
        $this->formatCode = $formatCode;
226
227 67
        return $this;
228
    }
229
230
    /**
231
     * Get Series Point Count.
232
     */
233 95
    public function getPointCount(): int
234
    {
235 95
        return $this->pointCount;
236
    }
237
238
    /**
239
     * Get fill color object.
240
     *
241
     * @return null|ChartColor|ChartColor[]
242
     */
243 91
    public function getFillColorObject()
244
    {
245 91
        return $this->fillColor;
246
    }
247
248 16
    private function stringToChartColor(string $fillString): ChartColor
249
    {
250 16
        $value = $type = '';
251 16
        if (str_starts_with($fillString, '*')) {
252 5
            $type = 'schemeClr';
253 5
            $value = substr($fillString, 1);
254 14
        } elseif (str_starts_with($fillString, '/')) {
255 3
            $type = 'prstClr';
256 3
            $value = substr($fillString, 1);
257 14
        } elseif ($fillString !== '') {
258 14
            $type = 'srgbClr';
259 14
            $value = $fillString;
260 14
            $this->validateColor($value);
261
        }
262
263 15
        return new ChartColor($value, null, $type);
264
    }
265
266 4
    private function chartColorToString(ChartColor $chartColor): string
267
    {
268 4
        $type = (string) $chartColor->getColorProperty('type');
269 4
        $value = (string) $chartColor->getColorProperty('value');
270 4
        if ($type === '' || $value === '') {
271 1
            return '';
272
        }
273 4
        if ($type === 'schemeClr') {
274 3
            return "*$value";
275
        }
276 4
        if ($type === 'prstClr') {
277 3
            return "/$value";
278
        }
279
280 4
        return $value;
281
    }
282
283
    /**
284
     * Get fill color.
285
     *
286
     * @return string|string[] HEX color or array with HEX colors
287
     */
288 9
    public function getFillColor(): string|array
289
    {
290 9
        if ($this->fillColor === null) {
291 5
            return '';
292
        }
293 4
        if (is_array($this->fillColor)) {
294 4
            $array = [];
295 4
            foreach ($this->fillColor as $chartColor) {
296 4
                $array[] = $this->chartColorToString($chartColor);
297
            }
298
299 4
            return $array;
300
        }
301
302 1
        return $this->chartColorToString($this->fillColor);
303
    }
304
305
    /**
306
     * Set fill color for series.
307
     *
308
     * @param ChartColor|ChartColor[]|string|string[] $color HEX color or array with HEX colors
309
     *
310
     * @return   $this
311
     */
312 38
    public function setFillColor($color): static
313
    {
314 38
        if (is_array($color)) {
315 16
            $this->fillColor = [];
316 16
            foreach ($color as $fillString) {
317 16
                if ($fillString instanceof ChartColor) {
318 9
                    $this->fillColor[] = $fillString;
319
                } else {
320 9
                    $this->fillColor[] = $this->stringToChartColor($fillString);
321
                }
322
            }
323 29
        } elseif ($color instanceof ChartColor) {
324 21
            $this->fillColor = $color;
325
        } else {
326 8
            $this->fillColor = $this->stringToChartColor($color);
327
        }
328
329 36
        return $this;
330
    }
331
332
    /**
333
     * Method for validating hex color.
334
     *
335
     * @param string $color value for color
336
     *
337
     * @return bool true if validation was successful
338
     */
339 14
    private function validateColor(string $color): bool
340
    {
341 14
        if (!preg_match('/^[a-f0-9]{6}$/i', $color)) {
342 2
            throw new Exception(sprintf('Invalid hex color for chart series (color: "%s")', $color));
343
        }
344
345 13
        return true;
346
    }
347
348
    /**
349
     * Get line width for series.
350
     */
351 6
    public function getLineWidth(): null|float|int
352
    {
353
        /** @var null|float|int */
354 6
        $temp = $this->lineStyleProperties['width'];
355
356 6
        return $temp;
357
    }
358
359
    /**
360
     * Set line width for the series.
361
     *
362
     * @return $this
363
     */
364 7
    public function setLineWidth(null|float|int $width): static
365
    {
366 7
        $this->lineStyleProperties['width'] = $width;
367
368 7
        return $this;
369
    }
370
371
    /**
372
     * Identify if the Data Series is a multi-level or a simple series.
373
     */
374 91
    public function isMultiLevelSeries(): ?bool
375
    {
376 91
        if (!empty($this->dataValues)) {
377 91
            return is_array(array_values($this->dataValues)[0]);
378
        }
379
380 2
        return null;
381
    }
382
383
    /**
384
     * Return the level count of a multi-level Data Series.
385
     */
386 18
    public function multiLevelCount(): int
387
    {
388 18
        $levelCount = 0;
389 18
        foreach (($this->dataValues ?? []) as $dataValueSet) {
390
            /** @var mixed[] $dataValueSet */
391 18
            $levelCount = max($levelCount, count($dataValueSet));
392
        }
393
394 18
        return $levelCount;
395
    }
396
397
    /**
398
     * Get Series Data Values.
399
     *
400
     * @return null|mixed[]
401
     */
402 95
    public function getDataValues(): ?array
403
    {
404 95
        return $this->dataValues;
405
    }
406
407
    /**
408
     * Get the first Series Data value.
409
     */
410 6
    public function getDataValue(): mixed
411
    {
412 6
        if ($this->dataValues === null) {
413
            return null;
414
        }
415 6
        $count = count($this->dataValues);
416 6
        if ($count == 0) {
417 3
            return null;
418 5
        } elseif ($count == 1) {
419 5
            return $this->dataValues[0];
420
        }
421
422 1
        return $this->dataValues;
423
    }
424
425
    /**
426
     * Set Series Data Values.
427
     *
428
     * @param mixed[] $dataValues
429
     *
430
     * @return $this
431
     */
432 67
    public function setDataValues(array $dataValues): static
433
    {
434 67
        $this->dataValues = Functions::flattenArray($dataValues);
435 67
        $this->pointCount = count($dataValues);
436
437 67
        return $this;
438
    }
439
440 95
    public function refresh(Worksheet $worksheet, bool $flatten = true): void
441
    {
442 95
        if ($this->dataSource !== null) {
443 94
            $calcEngine = Calculation::getInstance($worksheet->getParent());
444 94
            $newDataValues = Calculation::unwrapResult(
445 94
                $calcEngine->_calculateFormulaValue(
446 94
                    '=' . $this->dataSource,
447 94
                    null,
448 94
                    $worksheet->getCell('A1')
449 94
                )
450 94
            );
451 94
            if ($flatten) {
452 94
                $this->dataValues = Functions::flattenArray($newDataValues);
453 94
                foreach ($this->dataValues as &$dataValue) {
454 94
                    if (is_string($dataValue) && !empty($dataValue) && $dataValue[0] == '#') {
455
                        $dataValue = 0.0;
456
                    }
457
                }
458 94
                unset($dataValue);
459
            } else {
460 85
                [, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
461 85
                $dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange ?? ''));
462 85
                if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
463 68
                    $this->dataValues = Functions::flattenArray($newDataValues);
464
                } else {
465
                    /** @var array<int, mixed[]> */
466 21
                    $newDataValuesx = $newDataValues;
467
                    /** @var mixed[][] $newArray */
468 21
                    $newArray = array_values(array_shift($newDataValuesx) ?? []);
469 21
                    foreach ($newArray as $i => $newDataSet) {
470 21
                        $newArray[$i] = [$newDataSet];
471
                    }
472
473 21
                    foreach ($newDataValuesx as $newDataSet) {
474 21
                        $i = 0;
475 21
                        foreach ($newDataSet as $newDataVal) {
476 21
                            array_unshift($newArray[$i++], $newDataVal);
477
                        }
478
                    }
479 21
                    $this->dataValues = $newArray;
480
                }
481
            }
482 94
            $this->pointCount = count($this->dataValues ?? []);
483
        }
484
    }
485
486 45
    public function getScatterLines(): bool
487
    {
488 45
        return $this->scatterLines;
489
    }
490
491 28
    public function setScatterLines(bool $scatterLines): self
492
    {
493 28
        $this->scatterLines = $scatterLines;
494
495 28
        return $this;
496
    }
497
498 3
    public function getBubble3D(): bool
499
    {
500 3
        return $this->bubble3D;
501
    }
502
503 2
    public function setBubble3D(bool $bubble3D): self
504
    {
505 2
        $this->bubble3D = $bubble3D;
506
507 2
        return $this;
508
    }
509
510
    /**
511
     * Smooth Line. Must be specified for both DataSeries and DataSeriesValues.
512
     */
513
    private bool $smoothLine = false;
514
515
    /**
516
     * Get Smooth Line.
517
     */
518 11
    public function getSmoothLine(): bool
519
    {
520 11
        return $this->smoothLine;
521
    }
522
523
    /**
524
     * Set Smooth Line.
525
     *
526
     * @return $this
527
     */
528 15
    public function setSmoothLine(bool $smoothLine): static
529
    {
530 15
        $this->smoothLine = $smoothLine;
531
532 15
        return $this;
533
    }
534
535 91
    public function getLabelLayout(): ?Layout
536
    {
537 91
        return $this->labelLayout;
538
    }
539
540 9
    public function setLabelLayout(?Layout $labelLayout): self
541
    {
542 9
        $this->labelLayout = $labelLayout;
543
544 9
        return $this;
545
    }
546
547
    /** @param TrendLine[] $trendLines */
548 7
    public function setTrendLines(array $trendLines): self
549
    {
550 7
        $this->trendLines = $trendLines;
551
552 7
        return $this;
553
    }
554
555
    /** @return TrendLine[] */
556 92
    public function getTrendLines(): array
557
    {
558 92
        return $this->trendLines;
559
    }
560
561
    /**
562
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
563
     */
564 5
    public function __clone()
565
    {
566 5
        parent::__clone();
567 5
        $this->markerFillColor = clone $this->markerFillColor;
568 5
        $this->markerBorderColor = clone $this->markerBorderColor;
569 5
        if (is_array($this->fillColor)) {
570 1
            $fillColor = $this->fillColor;
571 1
            $this->fillColor = [];
572 1
            foreach ($fillColor as $color) {
573 1
                $this->fillColor[] = clone $color;
574
            }
575 5
        } elseif ($this->fillColor instanceof ChartColor) {
576 1
            $this->fillColor = clone $this->fillColor;
577
        }
578 5
        $this->labelLayout = ($this->labelLayout === null) ? null : clone $this->labelLayout;
579 5
        $trendLines = $this->trendLines;
580 5
        $this->trendLines = [];
581 5
        foreach ($trendLines as $trendLine) {
582 1
            $this->trendLines[] = clone $trendLine;
583
        }
584
    }
585
}
586