Completed
Push — master ( 87c3e9...49a3bf )
by Matt
19s queued 11s
created

Image::getSizeInBytes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

606
            $result .= ' ' . str_repeat('★', /** @scrutinizer ignore-type */ $this->rating);
Loading history...
607
        }
608
        return $result;
609
    }
610
}
611
612