Wander::getImageCount()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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