Test Failed
Branch master (d28506)
by Matt
06:00
created

Wander::setModifiedAt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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