Passed
Pull Request — master (#4142)
by Owen
11:33
created

BaseDrawing   F

Complexity

Total Complexity 80

Size/Duplication

Total Lines 555
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 80
eloc 167
dl 0
loc 555
rs 2
c 0
b 0
f 0
ccs 176
cts 176
cp 1

51 Methods

Rating   Name   Duplication   Size   Complexity  
A getImageWidth() 0 3 1
A setHeight() 0 12 4
A getDescription() 0 3 1
A setShadow() 0 5 1
A validEditAs() 0 3 1
A getHyperlink() 0 3 1
A getFlipVertical() 0 3 1
A setOffsetY() 0 5 1
A setFlipVertical() 0 5 1
A getOffsetY() 0 3 1
A setOffsetY2() 0 5 1
A setFlipHorizontal() 0 5 1
A getHeight() 0 3 1
A getCoordinates() 0 3 1
A getImageIndex() 0 3 1
A setHyperlink() 0 3 1
A getOpacity() 0 3 1
B setSizesAndType() 0 14 7
A setOffsetX2() 0 5 1
A getSrcRect() 0 3 1
A __clone() 0 10 4
A getOffsetX2() 0 3 1
A getHashCode() 0 17 2
A getShadow() 0 3 1
A setEditAs() 0 5 1
A setName() 0 5 1
A getEditAs() 0 3 1
A getWorksheet() 0 3 1
A __destruct() 0 3 1
A getOffsetY2() 0 3 1
A getOffsetX() 0 3 1
A getImageHeight() 0 3 1
B setWidthAndHeight() 0 18 7
A setCoordinates2() 0 5 1
A setDescription() 0 5 1
A getWidth() 0 3 1
A getRotation() 0 3 1
A getType() 0 3 1
A setCoordinates() 0 5 1
A getName() 0 3 1
A getCoordinates2() 0 3 1
A getFlipHorizontal() 0 3 1
A setSrcRect() 0 5 1
A getResizeProportional() 0 3 1
A __construct() 0 8 1
A setOffsetX() 0 5 1
A setWidth() 0 12 4
A setOpacity() 0 5 1
A setResizeProportional() 0 5 1
A setRotation() 0 5 1
B setWorksheet() 0 31 8

How to fix   Complexity   

Complex Class

Complex classes like BaseDrawing often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseDrawing, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Worksheet;
4
5
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
6
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
7
use PhpOffice\PhpSpreadsheet\IComparable;
8
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing\Shadow;
9
use SimpleXMLElement;
10
11
class BaseDrawing implements IComparable
12
{
13
    const EDIT_AS_ABSOLUTE = 'absolute';
14
    const EDIT_AS_ONECELL = 'oneCell';
15
    const EDIT_AS_TWOCELL = 'twoCell';
16
    private const VALID_EDIT_AS = [
17
        self::EDIT_AS_ABSOLUTE,
18
        self::EDIT_AS_ONECELL,
19
        self::EDIT_AS_TWOCELL,
20
    ];
21
22
    /**
23
     * The editAs attribute, used only with two cell anchor.
24
     */
25
    protected string $editAs = '';
26
27
    /**
28
     * Image counter.
29
     */
30
    private static int $imageCounter = 0;
31
32
    /**
33
     * Image index.
34
     */
35
    private int $imageIndex;
36
37
    /**
38
     * Name.
39
     */
40
    protected string $name = '';
41
42
    /**
43
     * Description.
44
     */
45
    protected string $description = '';
46
47
    /**
48
     * Worksheet.
49
     */
50
    protected ?Worksheet $worksheet = null;
51
52
    /**
53
     * Coordinates.
54
     */
55
    protected string $coordinates = 'A1';
56
57
    /**
58
     * Offset X.
59
     */
60
    protected int $offsetX = 0;
61
62
    /**
63
     * Offset Y.
64
     */
65
    protected int $offsetY = 0;
66
67
    /**
68
     * Coordinates2.
69
     */
70
    protected string $coordinates2 = '';
71
72
    /**
73
     * Offset X2.
74
     */
75
    protected int $offsetX2 = 0;
76
77
    /**
78
     * Offset Y2.
79
     */
80
    protected int $offsetY2 = 0;
81
82
    /**
83
     * Width.
84
     */
85
    protected int $width = 0;
86
87
    /**
88
     * Height.
89
     */
90
    protected int $height = 0;
91
92
    /**
93
     * Pixel width of image. See $width for the size the Drawing will be in the sheet.
94
     */
95
    protected int $imageWidth = 0;
96
97
    /**
98
     * Pixel width of image. See $height for the size the Drawing will be in the sheet.
99
     */
100
    protected int $imageHeight = 0;
101
102
    /**
103
     * Proportional resize.
104
     */
105
    protected bool $resizeProportional = true;
106
107
    /**
108
     * Rotation.
109
     */
110
    protected int $rotation = 0;
111
112
    protected bool $flipVertical = false;
113
114
    protected bool $flipHorizontal = false;
115
116
    /**
117
     * Shadow.
118
     */
119
    protected Shadow $shadow;
120
121
    /**
122
     * Image hyperlink.
123
     */
124
    private ?Hyperlink $hyperlink = null;
125
126
    /**
127
     * Image type.
128
     */
129
    protected int $type = IMAGETYPE_UNKNOWN;
130
131
    /** @var null|SimpleXMLElement|string[] */
132
    protected $srcRect = [];
133
134
    /**
135
     * Percentage multiplied by 100,000, e.g. 40% = 40,000.
136
     * Opacity=x is the same as transparency=100000-x.
137 195
     */
138
    protected ?int $opacity = null;
139
140 195
    /**
141
     * Create a new BaseDrawing.
142
     */
143 195
    public function __construct()
144 195
    {
145
        // Initialise values
146
        $this->setShadow();
147 50
148
        // Set image index
149 50
        ++self::$imageCounter;
150
        $this->imageIndex = self::$imageCounter;
151
    }
152 14
153
    public function __destruct()
154 14
    {
155
        $this->worksheet = null;
156
    }
157 56
158
    public function getImageIndex(): int
159 56
    {
160
        return $this->imageIndex;
161
    }
162 93
163
    public function getName(): string
164 93
    {
165
        return $this->name;
166 93
    }
167
168
    public function setName(string $name): self
169 64
    {
170
        $this->name = $name;
171 64
172
        return $this;
173
    }
174 78
175
    public function getDescription(): string
176 78
    {
177
        return $this->description;
178 78
    }
179
180
    public function setDescription(string $description): self
181 7
    {
182
        $this->description = $description;
183 7
184
        return $this;
185
    }
186
187
    public function getWorksheet(): ?Worksheet
188
    {
189
        return $this->worksheet;
190
    }
191 93
192
    /**
193 93
     * Set Worksheet.
194
     *
195 93
     * @param bool $overrideOld If a Worksheet has already been assigned, overwrite it and remove image from old Worksheet?
196 92
     */
197 92
    public function setWorksheet(?Worksheet $worksheet = null, bool $overrideOld = false): self
198 92
    {
199
        if ($this->worksheet === null) {
200
            // Add drawing to \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
201 1
            if ($worksheet !== null && !($this instanceof Drawing && $this->getPath() === '')) {
202
                $this->worksheet = $worksheet;
203 1
                $this->worksheet->getCell($this->coordinates);
204
                $this->worksheet->getDrawingCollection()->append($this);
205 1
            }
206 1
        } else {
207 1
            if ($overrideOld) {
208 1
                // Remove drawing from old \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
209
                $iterator = $this->worksheet->getDrawingCollection()->getIterator();
210 1
211
                while ($iterator->valid()) {
212
                    if ($iterator->current()->getHashCode() === $this->getHashCode()) {
213
                        $this->worksheet->getDrawingCollection()->offsetUnset($iterator->key());
214
                        $this->worksheet = null;
215 1
216
                        break;
217 1
                    }
218
                }
219
220
                // Set new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
221 93
                $this->setWorksheet($worksheet);
222
            } else {
223
                throw new PhpSpreadsheetException('A Worksheet has already been assigned. Drawings can only exist on one \\PhpOffice\\PhpSpreadsheet\\Worksheet.');
224 73
            }
225
        }
226 73
227
        return $this;
228
    }
229 91
230
    public function getCoordinates(): string
231 91
    {
232
        return $this->coordinates;
233 91
    }
234
235
    public function setCoordinates(string $coordinates): self
236 72
    {
237
        $this->coordinates = $coordinates;
238 72
239
        return $this;
240
    }
241 85
242
    public function getOffsetX(): int
243 85
    {
244
        return $this->offsetX;
245 85
    }
246
247
    public function setOffsetX(int $offsetX): self
248 72
    {
249
        $this->offsetX = $offsetX;
250 72
251
        return $this;
252
    }
253 70
254
    public function getOffsetY(): int
255 70
    {
256
        return $this->offsetY;
257 70
    }
258
259
    public function setOffsetY(int $offsetY): self
260 59
    {
261
        $this->offsetY = $offsetY;
262 59
263
        return $this;
264
    }
265 41
266
    public function getCoordinates2(): string
267 41
    {
268
        return $this->coordinates2;
269 41
    }
270
271
    public function setCoordinates2(string $coordinates2): self
272 28
    {
273
        $this->coordinates2 = $coordinates2;
274 28
275
        return $this;
276
    }
277 40
278
    public function getOffsetX2(): int
279 40
    {
280
        return $this->offsetX2;
281 40
    }
282
283
    public function setOffsetX2(int $offsetX2): self
284 28
    {
285
        $this->offsetX2 = $offsetX2;
286 28
287
        return $this;
288
    }
289 40
290
    public function getOffsetY2(): int
291 40
    {
292
        return $this->offsetY2;
293 40
    }
294
295
    public function setOffsetY2(int $offsetY2): self
296 83
    {
297
        $this->offsetY2 = $offsetY2;
298 83
299
        return $this;
300
    }
301 64
302
    public function getWidth(): int
303
    {
304 64
        return $this->width;
305 2
    }
306 2
307
    public function setWidth(int $width): self
308
    {
309
        // Resize proportional?
310 64
        if ($this->resizeProportional && $width != 0) {
311
            $ratio = $this->height / ($this->width != 0 ? $this->width : 1);
312 64
            $this->height = (int) round($ratio * $width);
313
        }
314
315 80
        // Set width
316
        $this->width = $width;
317 80
318
        return $this;
319
    }
320 82
321
    public function getHeight(): int
322
    {
323 82
        return $this->height;
324 29
    }
325 29
326
    public function setHeight(int $height): self
327
    {
328
        // Resize proportional?
329 82
        if ($this->resizeProportional && $height != 0) {
330
            $ratio = $this->width / ($this->height != 0 ? $this->height : 1);
331 82
            $this->width = (int) round($ratio * $height);
332
        }
333
334
        // Set height
335
        $this->height = $height;
336
337
        return $this;
338
    }
339
340
    /**
341
     * Set width and height with proportional resize.
342
     *
343
     * Example:
344
     * <code>
345 4
     * $objDrawing->setResizeProportional(true);
346
     * $objDrawing->setWidthAndHeight(160,120);
347 4
     * </code>
348 4
     *
349 4
     * @author Vincent@luo MSN:[email protected]
350 1
     */
351 1
    public function setWidthAndHeight(int $width, int $height): self
352 1
    {
353
        if ($this->width === 0 || $this->height === 0 || $width === 0 || $height === 0 || !$this->resizeProportional) {
354 1
            $this->width = $width;
355 1
            $this->height = $height;
356
        } else {
357
            $xratio = $width / $this->width;
358 4
            $yratio = $height / $this->height;
359 4
            if (($xratio * $this->height) < $height) {
360
                $this->height = (int) ceil($xratio * $this->height);
361
                $this->width = $width;
362 4
            } else {
363
                $this->width = (int) ceil($yratio * $this->width);
364
                $this->height = $height;
365 2
            }
366
        }
367 2
368
        return $this;
369
    }
370 70
371
    public function getResizeProportional(): bool
372 70
    {
373
        return $this->resizeProportional;
374 70
    }
375
376
    public function setResizeProportional(bool $resizeProportional): self
377 47
    {
378
        $this->resizeProportional = $resizeProportional;
379 47
380
        return $this;
381
    }
382 67
383
    public function getRotation(): int
384 67
    {
385
        return $this->rotation;
386 67
    }
387
388
    public function setRotation(int $rotation): self
389 57
    {
390
        $this->rotation = $rotation;
391 57
392
        return $this;
393
    }
394 195
395
    public function getShadow(): Shadow
396 195
    {
397
        return $this->shadow;
398 195
    }
399
400
    public function setShadow(?Shadow $shadow = null): self
401
    {
402
        $this->shadow = $shadow ?? new Shadow();
403
404
        return $this;
405
    }
406 48
407
    /**
408 48
     * Get hash code.
409 48
     *
410 48
     * @return string Hash code
411 48
     */
412 48
    public function getHashCode(): string
413 48
    {
414 48
        return md5(
415 48
            $this->name
416 48
            . $this->description
417 48
            . (($this->worksheet === null) ? '' : $this->worksheet->getHashCode())
418 48
            . $this->coordinates
419 48
            . $this->offsetX
420 48
            . $this->offsetY
421 48
            . $this->coordinates2
422 48
            . $this->offsetX2
423 48
            . $this->offsetY2
424
            . $this->width
425
            . $this->height
426
            . $this->rotation
427
            . $this->shadow->getHashCode()
428
            . __CLASS__
429 8
        );
430
    }
431 8
432 8
    /**
433 8
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
434 8
     */
435 8
    public function __clone()
436 8
    {
437
        $vars = get_object_vars($this);
438 8
        foreach ($vars as $key => $value) {
439
            if ($key == 'worksheet') {
440
                $this->worksheet = null;
441
            } elseif (is_object($value)) {
442
                $this->$key = clone $value;
443 2
            } else {
444
                $this->$key = $value;
445 2
            }
446
        }
447
    }
448 47
449
    public function setHyperlink(?Hyperlink $hyperlink = null): void
450 47
    {
451
        $this->hyperlink = $hyperlink;
452
    }
453
454
    public function getHyperlink(): ?Hyperlink
455
    {
456 89
        return $this->hyperlink;
457
    }
458 89
459 89
    /**
460
     * Set Fact Sizes and Type of Image.
461 89
     */
462 87
    protected function setSizesAndType(string $path): void
463 87
    {
464 87
        if ($this->imageWidth === 0 && $this->imageHeight === 0 && $this->type === IMAGETYPE_UNKNOWN) {
465
            $imageData = getimagesize($path);
466
467 89
            if (!empty($imageData)) {
468 89
                $this->imageWidth = $imageData[0];
469 89
                $this->imageHeight = $imageData[1];
470
                $this->type = $imageData[2];
471
            }
472
        }
473
        if ($this->width === 0 && $this->height === 0) {
474
            $this->width = $this->imageWidth;
475
            $this->height = $this->imageHeight;
476 6
        }
477
    }
478 6
479
    /**
480
     * Get Image Type.
481 1
     */
482
    public function getType(): int
483 1
    {
484
        return $this->type;
485
    }
486 1
487
    public function getImageWidth(): int
488 1
    {
489
        return $this->imageWidth;
490
    }
491 28
492
    public function getImageHeight(): int
493 28
    {
494
        return $this->imageHeight;
495
    }
496 40
497
    public function getEditAs(): string
498 40
    {
499
        return $this->editAs;
500 40
    }
501
502
    public function setEditAs(string $editAs): self
503 28
    {
504
        $this->editAs = $editAs;
505 28
506
        return $this;
507
    }
508
509
    public function validEditAs(): bool
510
    {
511 47
        return in_array($this->editAs, self::VALID_EDIT_AS, true);
512
    }
513 47
514
    /**
515
     * @return null|SimpleXMLElement|string[]
516
     */
517
    public function getSrcRect()
518
    {
519 7
        return $this->srcRect;
520
    }
521 7
522
    /**
523 7
     * @param null|SimpleXMLElement|string[] $srcRect
524
     */
525
    public function setSrcRect($srcRect): self
526 52
    {
527
        $this->srcRect = $srcRect;
528 52
529
        return $this;
530 52
    }
531
532
    public function setFlipHorizontal(bool $flipHorizontal): self
533 47
    {
534
        $this->flipHorizontal = $flipHorizontal;
535 47
536
        return $this;
537
    }
538 52
539
    public function getFlipHorizontal(): bool
540 52
    {
541
        return $this->flipHorizontal;
542 52
    }
543
544
    public function setFlipVertical(bool $flipVertical): self
545 47
    {
546
        $this->flipVertical = $flipVertical;
547 47
548
        return $this;
549
    }
550
551
    public function getFlipVertical(): bool
552
    {
553
        return $this->flipVertical;
554
    }
555
556
    public function setOpacity(?int $opacity): self
557
    {
558
        $this->opacity = $opacity;
559
560
        return $this;
561
    }
562
563
    public function getOpacity(): ?int
564
    {
565
        return $this->opacity;
566
    }
567
}
568