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

Wander::setFeaturedImage()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 6
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 15
rs 10
1
<?php
2
3
namespace App\Entity;
4
5
use ApiPlatform\Core\Annotation\ApiProperty;
6
use App\Repository\WanderRepository;
7
use ApiPlatform\Core\Annotation\ApiResource;
8
use ApiPlatform\Core\Annotation\ApiSubresource;
9
use DateInterval;
10
use DateTime;
11
use Doctrine\Common\Collections\ArrayCollection;
12
use Doctrine\Common\Collections\Collection;
13
use Symfony\Component\Serializer\Annotation\Groups;
14
use Doctrine\ORM\Mapping as ORM;
15
use App\EventListener\WanderUploadListener;
16
use Carbon\Carbon;
17
use Carbon\CarbonInterval;
18
use Doctrine\Common\Collections\Criteria;
19
20
use Doctrine\ORM\Mapping\Table;
21
use Doctrine\ORM\Mapping\Index;
22
23
24
/**
25
 * @ORM\Entity(repositoryClass=WanderRepository::class)
26
 *
27
 * @Table(indexes={@Index(name="ix_wander_start_time", columns={"start_time"})})
28
 *
29
 * @ORM\EntityListeners({
30
 *  WanderUploadListener::class, App\EventListener\WanderDeleteListener::class
31
 * })
32
 *
33
 * @ApiResource(
34
 *  collectionOperations={"get"={"normalization_context"={"groups"="wander:list"}}},
35
 *  itemOperations={"get"={"normalization_context"={"groups"="wander:item"}}},
36
 *  order={"endTime"="ASC"}
37
 * )
38
 * @ORM\HasLifecycleCallbacks()
39
 *
40
 */
41
class Wander
42
{
43
    /**
44
     * @ORM\Id
45
     * @ORM\GeneratedValue
46
     * @ORM\Column(type="integer")
47
     *
48
     * @Groups({"wander:list", "wander:item"})
49
     */
50
    private $id;
51
52
    /**
53
     * @ORM\Column(type="string", length=1024)
54
     *
55
     * @Groups({"wander:list", "wander:item"})
56
     */
57
    private $title;
58
59
    /**
60
     * @ORM\Column(type="datetime")
61
     *
62
     * @Groups({"wander:list", "wander:item"})
63
     */
64
    private $startTime;
65
66
    /**
67
     * @ORM\Column(type="datetime")
68
     *
69
     * @Groups({"wander:list", "wander:item"})
70
     */
71
    private $endTime;
72
73
    /**
74
     * @ORM\Column(type="text", nullable=true)
75
     *
76
     * @Groups({"wander:list", "wander:item"})
77
     */
78
    private $description;
79
80
    /**
81
     * @ORM\Column(type="string", length=255)
82
     *
83
     * @Groups({"wander:list", "wander:item"})
84
     */
85
    private $gpxFilename;
86
87
    /**
88
     * @ORM\OneToMany(targetEntity=Image::class, mappedBy="wander", cascade={"persist"})
89
     *
90
     * @Groups({"wander:list", "wander:item"})
91
     * @ApiSubresource
92
     */
93
    private $images;
94
95
    /**
96
     * @ORM\Column(type="float", nullable=true)
97
     *
98
     * Distance walked, in metres.
99
     *
100
     */
101
    private $distance;
102
103
    /**
104
     * @ORM\Column(type="float", nullable=true)
105
     */
106
    private $avgSpeed;
107
108
    /**
109
     * @ORM\Column(type="float", nullable=true)
110
     */
111
    private $avgPace;
112
113
    /**
114
     * @ORM\Column(type="float", nullable=true)
115
     */
116
    private $minAltitude;
117
118
    /**
119
     * @ORM\Column(type="float", nullable=true)
120
     */
121
    private $maxAltitude;
122
123
    /**
124
     * @ORM\Column(type="float", nullable=true)
125
     */
126
    private $cumulativeElevationGain;
127
128
    /**
129
     * @var string|null
130
     *
131
     * @ApiProperty(iri="http://schema.org/contentUrl")
132
     * @Groups({"wander:list", "wander:item"})
133
     */
134
    public $contentUrl;
135
136
    /**
137
     * @ORM\Column(type="array", nullable=true)
138
     */
139
    private $centroid = [];
140
141
    /**
142
     * @ORM\Column(type="float", nullable=true)
143
     */
144
    private $angleFromHome;
145
146
    public function __construct()
147
    {
148
        $this->images = new ArrayCollection();
149
    }
150
151
    public function getId(): ?int
152
    {
153
        return $this->id;
154
    }
155
156
    public function getTitle(): ?string
157
    {
158
        return $this->title;
159
    }
160
161
    public function setTitle(string $title): self
162
    {
163
        $this->title = $title;
164
165
        return $this;
166
    }
167
168
    public function getStartTime(): ?\DateTimeInterface
169
    {
170
        return $this->startTime;
171
    }
172
173
    public function setStartTime(\DateTimeInterface $startTime): self
174
    {
175
        $this->startTime = $startTime;
176
177
        return $this;
178
    }
179
180
    public function getEndTime(): ?\DateTimeInterface
181
    {
182
        return $this->endTime;
183
    }
184
185
    public function setEndTime(\DateTimeInterface $endTime): self
186
    {
187
        $this->endTime = $endTime;
188
189
        return $this;
190
    }
191
192
    public function getDescription(): ?string
193
    {
194
        return $this->description;
195
    }
196
197
    public function setDescription(?string $description): self
198
    {
199
        $this->description = $description;
200
201
        return $this;
202
    }
203
204
    public function getGpxFilename(): ?string
205
    {
206
        return $this->gpxFilename;
207
    }
208
209
    public function setGpxFilename(string $gpxFilename): self
210
    {
211
        $this->gpxFilename = $gpxFilename;
212
213
        return $this;
214
    }
215
216
    public function isTimeLengthSuspicious()
217
    {
218
        $interval = $this->startTime->diff($this->endTime, true);
219
        return $interval->h > 12;
220
    }
221
222
    /**
223
     * @return Collection|Image[]
224
     */
225
    public function getImages(): Collection
226
    {
227
        return $this->images;
228
    }
229
230
    /**
231
     * @return Collection|Image[]
232
     */
233
    public function getImagesWithNoTitle(): Collection
234
    {
235
        $criteria = Criteria::create()
236
            ->where(Criteria::expr()->isNull('title'));
237
        return $this->getImages()->matching($criteria);
238
    }
239
240
    /**
241
     * @return Collection|Image[]
242
     */
243
    public function getImagesWithNoLatLng(): Collection
244
    {
245
        $criteria = Criteria::create()
246
            ->where(Criteria::expr()->isNull('latlng'));
247
        return $this->getImages()->matching($criteria);
248
    }
249
250
    /**
251
     * @return Collection|Image[]
252
     */
253
    public function getImagesWithNoLocation(): Collection
254
    {
255
        $criteria = Criteria::create()
256
            ->where(Criteria::expr()->isNull('location'));
257
        return $this->getImages()->matching($criteria);
258
    }
259
260
    /**
261
     * @return Collection|Image[]
262
     */
263
    public function getImagesWithNoRating(): Collection
264
    {
265
        $criteria = Criteria::create()
266
            ->where(Criteria::expr()->isNull('rating'));
267
        return $this->getImages()->matching($criteria);
268
    }
269
270
    /**
271
     * @return Collection|Image[]
272
     */
273
    public function getImagesWithNoTags(): Collection
274
    {
275
        return $this->getImages()->filter(function($image) {
276
            return $image->getTags()->isEmpty();
277
        });
278
    }
279
280
    /**
281
     * @return Collection|Image[]
282
     */
283
    public function getImagesWithNoAutoTags(): Collection
284
    {
285
        return $this->getImages()->filter(function($image) {
286
            return $image->getAutoTagsCount() == 0;
287
        });
288
    }
289
290
    public function addImage(Image $image): self
291
    {
292
        if (!$this->images->contains($image)) {
293
            $this->images[] = $image;
294
            $image->setWander($this);
295
        }
296
297
        return $this;
298
    }
299
300
    public function removeImage(Image $image): self
301
    {
302
        $image->setWander(null);
303
        $this->images->removeElement($image);
304
305
        return $this;
306
    }
307
308
    /**
309
     * @ORM\PreRemove
310
     */
311
    public function removeAllImages(): self
312
    {
313
        $images = $this->images;
314
        foreach ($images as $image) {
315
            $this->removeImage($image);
316
        }
317
        return $this;
318
    }
319
320
    public function getDistance(): ?float
321
    {
322
        return $this->distance;
323
    }
324
325
    public function setDistance(?float $distance): self
326
    {
327
        $this->distance = $distance;
328
329
        return $this;
330
    }
331
332
    public function getAvgSpeed(): ?float
333
    {
334
        return $this->avgSpeed;
335
    }
336
337
    public function setAvgSpeed(?float $avgSpeed): self
338
    {
339
        $this->avgSpeed = $avgSpeed;
340
341
        return $this;
342
    }
343
344
    public function getAvgPace(): ?float
345
    {
346
        return $this->avgPace;
347
    }
348
349
    public function setAvgPace(?float $avgPace): self
350
    {
351
        $this->avgPace = $avgPace;
352
353
        return $this;
354
    }
355
356
    public function getMinAltitude(): ?float
357
    {
358
        return $this->minAltitude;
359
    }
360
361
    public function setMinAltitude(?float $minAltitude): self
362
    {
363
        $this->minAltitude = $minAltitude;
364
365
        return $this;
366
    }
367
368
    public function getMaxAltitude(): ?float
369
    {
370
        return $this->maxAltitude;
371
    }
372
373
    public function setMaxAltitude(?float $maxAltitude): self
374
    {
375
        $this->maxAltitude = $maxAltitude;
376
377
        return $this;
378
    }
379
380
    public function getCumulativeElevationGain(): ?float
381
    {
382
        return $this->cumulativeElevationGain;
383
    }
384
385
    public function setCumulativeElevationGain(?float $cumulativeElevationGain): self
386
    {
387
        $this->cumulativeElevationGain = $cumulativeElevationGain;
388
389
        return $this;
390
    }
391
392
    public function getDuration(): ?CarbonInterval
393
    {
394
        if (!isset($this->startTime, $this->endTime)) {
395
            return null;
396
        }
397
398
        $difference = CarbonInterval::instance($this->startTime->diff($this->endTime));
399
        return $difference;
400
    }
401
402
    /**
403
     * @return array<float>
404
     */
405
    public function getCentroid(): ?array
406
    {
407
        return $this->centroid;
408
    }
409
410
    /**
411
     * @param array<float> $centroid
412
     */
413
    public function setCentroid(?array $centroid): self
414
    {
415
        $this->centroid = $centroid;
416
417
        return $this;
418
    }
419
420
    // We could calculate the angle from the Centroid each time, but
421
    // for now I'm just going to store it to save time.
422
    public function getAngleFromHome(): ?float
423
    {
424
        return $this->angleFromHome;
425
    }
426
427
    public function setAngleFromHome(?float $angleFromHome): self
428
    {
429
        $this->angleFromHome = $angleFromHome;
430
431
        return $this;
432
    }
433
434
    // Utilities
435
436
    // TODO: This is more like display code. Perhaps this should be in
437
    // a Twig extension and we should stick to storing the angle in here.
438
439
    /**
440
     * @var array<int, string>
441
     */
442
    private static $compass = [
443
        0 => 'N',
444
        1 => 'NE',
445
        2 => 'NE',
446
        3 => 'E',
447
        4 => 'E',
448
        5 => 'SE',
449
        6 => 'SE',
450
        7 => 'S',
451
        8 => 'S',
452
        9 => 'SW',
453
        10 => 'SW',
454
        11 => 'W',
455
        12 => 'W',
456
        13 => 'NW',
457
        14 => 'NW',
458
        15 => 'N'
459
      ];
460
461
    /**
462
     * @ORM\Column(type="text", nullable=true)
463
     *
464
     * @Groups({"wander:list", "wander:item"})
465
     *
466
     */
467
    private $geoJson;
468
469
    /**
470
     * @ORM\OneToOne(targetEntity=Image::class, mappedBy="featuringWander", cascade={"persist"})
471
     */
472
    private $featuredImage;
473
474
    public function getSector(): ?string
475
    {
476
        if ($this->angleFromHome !== null) {
477
            if ($this->angleFromHome >= 0 && $this->angleFromHome < 360.0) {
478
                return self::$compass[floor($this->angleFromHome / 22.5)];
479
            }
480
        }
481
        return null;
482
    }
483
484
    public function getCentroidAsString(): ?string {
485
        if ($this->centroid !== null) {
486
            return implode(", ", $this->centroid);
487
        }
488
        return null;
489
    }
490
491
    // TODO: Put this in but didn't use it in the end; maybe I don't need it
492
    // as in Twig we can use wander.images.count anyway. Take out?
493
    public function getImageCount(): int
494
    {
495
        // https://stackoverflow.com/a/8511611/300836
496
        return $this->images->count();
497
    }
498
499
    public function __toString():string
500
    {
501
        $result = $this->title ?? '';
502
        if (isset($this->startTime)) {
503
            $result .= ' (' . $this->startTime->format('j M Y') . ')';
504
        }
505
        return $result;
506
    }
507
508
    public function getGeoJson(): ?string
509
    {
510
        return $this->geoJson;
511
    }
512
513
    public function setGeoJson(?string $geoJson): self
514
    {
515
        $this->geoJson = $geoJson;
516
517
        return $this;
518
    }
519
520
    public function getFeaturedImage(): ?Image
521
    {
522
        return $this->featuredImage;
523
    }
524
525
    public function hasFeaturedImage(): bool
526
    {
527
        return $this->featuredImage !== null;
528
    }
529
530
    public function setFeaturedImage(?Image $featuredImage): self
531
    {
532
        // unset the owning side of the relation if necessary
533
        if ($this->featuredImage !== null) {
534
            $this->featuredImage->setFeaturingWander(null);
535
        }
536
537
        // set the owning side of the relation if necessary
538
        if ($featuredImage !== null && $featuredImage->getFeaturingWander() !== $this) {
539
            $featuredImage->setFeaturingWander($this);
540
        }
541
542
        $this->featuredImage = $featuredImage;
543
544
        return $this;
545
    }
546
}
547