Passed
Push — master ( 028b7a...8da5b1 )
by Matt
05:44 queued 55s
created

Image::setOriginalName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Entity;
4
5
use App\EventListener\ImageCalculatedFieldSetterListener;
6
use App\EventListener\WanderUploadListener;
7
use App\Repository\ImageRepository;
8
use Doctrine\Common\Collections\ArrayCollection;
9
use Doctrine\Common\Collections\Collection;
10
use Doctrine\ORM\Mapping as ORM;
11
use Symfony\Component\HttpFoundation\File\File;
12
use Vich\UploaderBundle\Mapping\Annotation as Vich;
13
use Symfony\Component\Validator\Constraints as Assert;
14
use Symfony\Component\Serializer\Annotation\Groups;
15
use Symfony\Component\Serializer\Annotation\Ignore;
16
use App\EventListener\SearchIndexer;
17
use Beelab\TagBundle\Tag\TaggableInterface;
18
use Beelab\TagBundle\Tag\TagInterface;
19
use Doctrine\ORM\Event\LifecycleEventArgs;
20
use Doctrine\ORM\Mapping\Table;
21
use Doctrine\ORM\Mapping\Index;
22
23
/**
24
 *
25
 * @ORM\Entity(repositoryClass=ImageRepository::class)
26
 *
27
 * @ORM\EntityListeners({
28
 *     ImageCalculatedFieldSetterListener::class,
29
 *     SearchIndexer::class
30
 * })
31
 *
32
 * @ORM\HasLifecycleCallbacks()
33
 *
34
 * This is just to control the stuff that goes back from our one controller
35
 * action that returns a JSON response, ImageController::upload
36
 *
37
 * @Vich\Uploadable
38
 */
39
40
class Image implements TaggableInterface
41
{
42
    /**
43
     * @ORM\Id
44
     * @ORM\GeneratedValue
45
     * @ORM\Column(type="integer")
46
     *
47
     * @Groups({"wander:item", "image:list"})
48
     */
49
    private $id;
50
51
    // TODO: We probably don't want this massive field being returned
52
    // as part of any API response, etc.
53
    /**
54
     * @Vich\UploadableField(mapping="image", fileNameProperty="name", size="sizeInBytes",
55
     *  mimeType="mimeType", originalName="originalName", dimensions="dimensions")
56
     *
57
     * @Ignore()
58
     */
59
    private $imageFile;
60
61
    /**
62
     * @ORM\Column(type="string", length=255, nullable=true)
63
     *
64
     * @Groups({"wander:item", "image:list"})
65
     */
66
    private $name; // For Vich, not for us. We use Title.
67
68
    /**
69
     * @ORM\Column(type="string", length=255, nullable=true)
70
     *
71
     * @Groups({"wander:item", "image:list"})
72
     */
73
    private $title;
74
75
    /**
76
     * @ORM\Column(type="text", nullable=true)
77
     *
78
     * @Groups({"wander:item", "image:list"})
79
     */
80
    private $description;
81
82
    /**
83
     * @ORM\Column(type="integer", nullable=true)
84
     *
85
     * @Groups({"wander:item"})
86
     */
87
    private $sizeInBytes;
88
89
    /**
90
     * @ORM\Column(type="string", length=255, nullable=true)
91
     *
92
     * @Groups({"wander:item"})
93
     */
94
    private $mimeType;
95
96
    /**
97
     * @ORM\Column(type="string", length=255, nullable=true)
98
     *
99
     * @Groups({"wander:item"})
100
     */
101
    private $originalName;
102
103
    /**
104
     * @ORM\Column(type="simple_array", nullable=true)
105
     *
106
     * @Groups({"wander:item"})
107
     */
108
    private $dimensions = [];
109
110
    /**
111
     * @ORM\Column(type="datetime")
112
     *
113
     * @Groups({"wander:item"})
114
     *
115
     * @var \DateTimeInterface|null
116
     */
117
    private $updatedAt;
118
119
    /**
120
     * @ORM\Column(type="simple_array", nullable=true)
121
     * @Assert\AtLeastOneOf({
122
     *   @Assert\Count(
123
     *      min = 2,
124
     *      max = 2,
125
     *      exactMessage = "Co-ordinates must consist of a latitude, longitude pair (or nothing.)"
126
     *   ),
127
     *   @Assert\Count(
128
     *      min = 0,
129
     *      max = 0,
130
     *      exactMessage = "Co-ordinates must consist of a latitude, longitude pair (or nothing.)"
131
     *   )
132
     * })
133
     *
134
     * @Groups({"wander:item", "image:list"})
135
     *
136
     */
137
    private $latlng = [];
138
139
    /**
140
     * @var Collection
141
     * @ORM\ManyToMany(targetEntity="Tag")
142
     */
143
    private $tags;
144
145
    /**
146
     * @ORM\Column(type="datetime", nullable=true)
147
     *
148
     * @Groups({"wander:item"})
149
     */
150
    private $capturedAt;
151
152
    /**
153
     * @ORM\Column(type="integer", nullable=true)
154
     * @Groups({"wander:item"})
155
     */
156
    private $rating;
157
158
159
    // TODO: This @Ignore was here from when this was a many-to-many. Do we still
160
    // need it?
161
    /**
162
     * @ORM\ManyToOne(targetEntity=Wander::class, inversedBy="images")
163
     *
164
     * @Ignore()
165
     */
166
    private $wander;
167
168
    public function __construct()
169
    {
170
        $this->tags = new ArrayCollection();
171
    }
172
173
    /**
174
     * If manually uploading a file (i.e. not using Symfony Form) ensure an instance
175
     * of 'UploadedFile' is injected into this setter to trigger the update. If this
176
     * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
177
     * must be able to accept an instance of 'File' as the bundle will inject one here
178
     * during Doctrine hydration.
179
     *
180
     * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $imageFile
181
     */
182
    public function setImageFile(?File $imageFile = null): void
183
    {
184
        $this->imageFile = $imageFile;
185
186
        if (null !== $imageFile) {
187
            // It is required that at least one field changes if you are using doctrine
188
            // otherwise the event listeners won't be called and the file is lost
189
            $this->updatedAt = new \DateTimeImmutable();
190
        }
191
    }
192
193
    /**
194
     * @Ignore()
195
     */
196
    public function getImageFile(): ?File
197
    {
198
        return $this->imageFile;
199
    }
200
201
    public function getId(): ?int
202
    {
203
        return $this->id;
204
    }
205
206
    public function getName(): ?string
207
    {
208
        return $this->name;
209
    }
210
211
    public function setName(?string $name): self
212
    {
213
        $this->name = $name;
214
215
        return $this;
216
    }
217
218
    public function getTitle(): ?string
219
    {
220
        return $this->title;
221
    }
222
223
    public function getTitleOrId(): string
224
    {
225
        if ($this->title !== null && $this->title != "") {
226
            return $this->title;
227
        }
228
        return (string) "Image " . $this->id;
229
    }
230
231
    public function setTitle(?string $title): self
232
    {
233
        $this->title = $title;
234
235
        return $this;
236
    }
237
238
    public function getDescription(): ?string
239
    {
240
        return $this->description;
241
    }
242
243
    public function setDescription(?string $description): self
244
    {
245
        $this->description = $description;
246
247
        return $this;
248
    }
249
250
    public function getSizeInBytes(): ?int
251
    {
252
        return $this->sizeInBytes;
253
    }
254
255
    public function setSizeInBytes(?int $sizeInBytes): self
256
    {
257
        $this->sizeInBytes = $sizeInBytes;
258
259
        return $this;
260
    }
261
262
    public function getMimeType(): ?string
263
    {
264
        return $this->mimeType;
265
    }
266
267
    public function setMimeType(?string $mimeType): self
268
    {
269
        $this->mimeType = $mimeType;
270
271
        return $this;
272
    }
273
274
    public function getOriginalName(): ?string
275
    {
276
        return $this->originalName;
277
    }
278
279
    public function setOriginalName(?string $originalName): self
280
    {
281
        $this->originalName = $originalName;
282
283
        return $this;
284
    }
285
286
    public function getDimensions(): ?array
287
    {
288
        return $this->dimensions;
289
    }
290
291
    public function setDimensions(?array $dimensions): self
292
    {
293
        $this->dimensions = $dimensions;
294
295
        return $this;
296
    }
297
298
    public function getUpdatedAt(): ?\DateTimeInterface
299
    {
300
        return $this->updatedAt;
301
    }
302
303
    public function setUpdatedAt(\DateTimeInterface $updatedAt): self
304
    {
305
        $this->updatedAt = $updatedAt;
306
        return $this;
307
    }
308
309
    public function getLatitude(): ?float
310
    {
311
        if ($this->latlng === null ||
312
            !is_array($this->latlng) ||
313
            empty($this->latlng)) {
314
            return null;
315
        }
316
        return $this->latlng[0];
317
    }
318
319
    public function getLongitude(): ?float
320
    {
321
        if ($this->latlng === null ||
322
            !is_array($this->latlng) ||
323
            empty($this->latlng)) {
324
            return null;
325
        }
326
        return $this->latlng[1];
327
    }
328
329
    public function getLatlng(): ?array
330
    {
331
        return $this->latlng;
332
    }
333
334
    public function hasLatlng(): bool
335
    {
336
        return is_array($this->latlng) && count($this->latlng) == 2;
337
    }
338
339
    public function setLatlng(?array $latlng): self
340
    {
341
        $this->latlng = $latlng;
342
343
        return $this;
344
    }
345
346
    public function addTag(TagInterface $tag): void
347
    {
348
        if (!$this->tags->contains($tag)) {
349
            $this->tags->add($tag);
350
        }
351
    }
352
353
    public function clearTags(): void
354
    {
355
        $this->tags->clear();
356
    }
357
358
    public function removeTag(TagInterface $tag): void
359
    {
360
        $this->tags->removeElement($tag);
361
    }
362
363
    public function hasTag(TagInterface $tag): bool
364
    {
365
        return $this->tags->contains($tag);
366
    }
367
368
    /**
369
     * @return iterable<TagInterface>
370
     */
371
    public function getTags(): iterable
372
    {
373
        return $this->tags;
374
    }
375
376
    /**
377
     * @param Collection<TagInterface> $tags
378
     */
379
    public function setTags($tags): self
380
    {
381
        $this->clearTags();
382
        foreach ($tags as $tag) {
383
            $this->addTag($tag);
384
        }
385
        return $this;
386
    }
387
388
    /** @var string|null */
389
    private $tagsText;
390
391
    public function setTagsText(?string $tagsText): void
392
    {
393
        $this->tagsText = $tagsText;
394
        $this->updatedAt = new \DateTimeImmutable();
395
    }
396
397
    public function getTagsText(): ?string
398
    {
399
        $this->tagsText = \implode(', ', $this->tags->toArray());
400
        return $this->tagsText;
401
    }
402
403
    /**
404
     * @ORM\PostLoad
405
     */
406
    public function postLoad(): void
407
    {
408
        // Bodge to workaround behaviour of BeelabTagBundle, which updates
409
        // tags on persist, but only from the text tags. So if you don't
410
        // get/set the tags text, when you persist your entity all its
411
        // tags disappear. Sigh.
412
        $this->getTagsText();
413
    }
414
415
    /**
416
     * @return array<string>
417
     */
418
    public function getTagNames(): array
419
    {
420
        return empty($this->tagsText) ? [] : \array_map('trim', explode(',', $this->tagsText));
421
    }
422
423
    public function getCapturedAt(): ?\DateTimeInterface
424
    {
425
        return $this->capturedAt;
426
    }
427
428
    public function setCapturedAt(\DateTimeInterface $capturedAt): self
429
    {
430
        $this->capturedAt = $capturedAt;
431
432
        return $this;
433
    }
434
435
    public function hasCapturedAt(): bool
436
    {
437
        return $this->capturedAt !== null;
438
    }
439
440
    public function getWander(): ?Wander
441
    {
442
        return $this->wander;
443
    }
444
445
    public function setWander(?Wander $wander): self
446
    {
447
        $this->wander = $wander;
448
        return $this;
449
    }
450
451
    public function hasWander(): bool
452
    {
453
        return ($this->wander !== null);
454
    }
455
456
    public function getRating(): ?int
457
    {
458
        return $this->rating;
459
    }
460
461
    public function setRating(?int $rating): self
462
    {
463
        $this->rating = $rating;
464
465
        return $this;
466
    }
467
468
469
    /* Computed (set up by Doctrine postLoad listener) */
470
471
    /**
472
     * @Groups({"wander:item"})
473
     */
474
    private $imageUri;
475
476
    /**
477
     * @Groups({"wander:item", "image:list"})
478
     */
479
    private $markerImageUri;
480
481
    /**
482
     * @Groups({"wander:item", "image:list"})
483
     */
484
    private $mediumImageUri;
485
486
    /**
487
     * @Groups({"wander:item", "image:list"})
488
     */
489
    private $imageShowUri;
490
491
    /**
492
     * @ORM\Column(type="array", nullable=true)
493
     * @var ?string[]
494
     */
495
    private $autoTags = [];
496
497
    /**
498
     * @ORM\Column(type="string", length=255, nullable=true)
499
     */
500
    private $location;
501
502
    /**
503
     * @ORM\OneToOne(targetEntity=Wander::class, inversedBy="featuredImage", cascade={"persist"})
504
     */
505
    private $featuringWander;
506
507
    /**
508
     * @ORM\Column(type="array", nullable=true)
509
     */
510
    private $textTags = [];
511
512
    public function setImageUri($imageUri) {
513
        $this->imageUri = $imageUri;
514
    }
515
516
    public function getImageUri(): ?string {
517
        return $this->imageUri;
518
    }
519
520
    public function setMarkerImageUri($markerImageUri) {
521
        $this->markerImageUri = $markerImageUri;
522
    }
523
    public function getMarkerImageUri(): ?string {
524
        return $this->markerImageUri;
525
    }
526
527
    public function setMediumImageUri($mediumImageUri) {
528
        $this->mediumImageUri = $mediumImageUri;
529
    }
530
    public function getMediumImageUri(): ?string {
531
        return $this->mediumImageUri;
532
    }
533
534
    public function setImageShowUri($imageShowUri) {
535
        $this->imageShowUri = $imageShowUri;
536
    }
537
    public function getImageShowUri(): ?string {
538
        return $this->imageShowUri;
539
    }
540
541
    /**
542
     * @return ?string[]
543
     */
544
    public function getAutoTags(): array
545
    {
546
        return $this->autoTags;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->autoTags could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
547
    }
548
549
    /**
550
     * @param ?string[] $autoTags
551
     */
552
    public function setAutoTags(?array $autoTags): self
553
    {
554
        $this->autoTags = $autoTags;
555
556
        return $this;
557
    }
558
    public function getAutoTagsCount(): int
559
    {
560
        if (is_array($this->autoTags)) {
561
            return count($this->autoTags);
562
        }
563
        return 0;
564
    }
565
566
    public function getLocation(): ?string
567
    {
568
        return $this->location;
569
    }
570
571
    public function hasLocation(): bool
572
    {
573
        return $this->location !== null && $this->location <> '';
574
    }
575
576
    public function setLocation(?string $location): self
577
    {
578
        $this->location = $location;
579
580
        return $this;
581
    }
582
583
    public function getFeaturingWander(): ?Wander
584
    {
585
        return $this->featuringWander;
586
    }
587
588
    public function setFeaturingWander(?Wander $featuringWander): self
589
    {
590
        $this->featuringWander = $featuringWander;
591
592
        return $this;
593
    }
594
595
    public function setAsFeaturedImage(): void
596
    {
597
        $wander = $this->wander;
598
        if ($wander === null) {
599
            throw new \Exception("Can't call setAsFeaturedImage unless the Image is associated with a Wander.");
600
        }
601
        $this->setFeaturingWander($wander);
602
    }
603
604
    // Used when building drop-down list of Images to choose as selection on Wander edit screen
605
    public function __toString(): string
606
    {
607
        $result = $this->title ?? (string) $this->id;
608
        if (isset($this->capturedAt)) {
609
            $result .= ' (' . $this->capturedAt->format('j M Y') . ')';
610
        }
611
        if (isset($this->rating)) {
612
            $result .= ' ' . str_repeat('★', $this->rating);
0 ignored issues
show
Bug introduced by
It seems like $this->rating can also be of type null; however, parameter $times of str_repeat() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

612
            $result .= ' ' . str_repeat('★', /** @scrutinizer ignore-type */ $this->rating);
Loading history...
613
        }
614
        return $result;
615
    }
616
617
    public function getTextTags(): ?array
618
    {
619
        return $this->textTags;
620
    }
621
622
    public function getTextTagsCount(): int
623
    {
624
        if (is_array($this->textTags)) {
0 ignored issues
show
introduced by
The condition is_array($this->textTags) is always true.
Loading history...
625
            return count($this->textTags);
626
        }
627
        return 0;
628
    }
629
630
631
    public function setTextTags(?array $textTags): self
632
    {
633
        $this->textTags = $textTags;
634
635
        return $this;
636
    }
637
}
638
639