Passed
Push — master ( 9f30a7...b58c9f )
by Adrien
03:57
created

Bookable::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 9
ccs 7
cts 7
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\DBAL\Types\BookableStateType;
8
use Application\DBAL\Types\BookingTypeType;
9
use Application\Repository\BookableTagRepository;
10
use Application\Traits\HasCode;
11
use Application\Traits\HasDescription;
12
use Application\Traits\HasName;
13
use Application\Traits\HasRemarks;
14
use Cake\Chronos\Date;
15
use Doctrine\Common\Collections\ArrayCollection;
16
use Doctrine\Common\Collections\Collection;
17
use Doctrine\ORM\Mapping as ORM;
18
use GraphQL\Doctrine\Annotation as API;
19
use Money\Money;
20
21
/**
22
 * An item that can be booked by a user
23
 *
24
 * @ORM\Entity(repositoryClass="Application\Repository\BookableRepository")
25
 * @API\Filters({
26
 *     @API\Filter(field="custom", operator="Application\Api\Input\Operator\BookableUsageOperatorType", type="id"),
27
 * })
28
 */
29
class Bookable extends AbstractModel
30
{
31
    use HasName;
32
    use HasDescription;
33
    use HasCode;
34
    use HasRemarks;
35
36
    /**
37
     * @var Money
38
     *
39
     * @ORM\Column(type="Money", options={"default" = 0})
40
     */
41
    private $initialPrice;
42
43
    /**
44
     * @var Money
45
     *
46
     * @ORM\Column(type="Money", options={"default" = 0})
47
     */
48
    private $periodicPrice;
49
50
    /**
51
     * @var Money
52
     *
53
     * @ORM\Column(type="Money",  options={"default" = 0, "unsigned" = true})
54
     */
55
    private $purchasePrice;
56
57
    /**
58
     * @var int
59
     *
60
     * @ORM\Column(type="smallint", options={"default" = "-1"})
61
     */
62
    private $simultaneousBookingMaximum = 1;
63
64
    /**
65
     * @var string
66
     *
67
     * @ORM\Column(type="BookingType", length=10, options={"default" = BookingTypeType::SELF_APPROVED})
68
     */
69
    private $bookingType = BookingTypeType::SELF_APPROVED;
70
71
    /**
72
     * @var bool
73
     *
74
     * @ORM\Column(type="boolean", options={"default" = 1})
75
     */
76
    private $isActive = true;
77
78
    /**
79
     * @var string
80
     *
81
     * @ORM\Column(type="BookableState", length=10, options={"default" = BookableStateType::GOOD})
82
     */
83
    private $state = BookableStateType::GOOD;
84
85
    /**
86
     * @var null|Date
87
     * @ORM\Column(type="date", nullable=true)
88
     */
89
    private $verificationDate;
90
91
    /**
92
     * @var BookableTag
93
     *
94
     * @ORM\ManyToMany(targetEntity="BookableTag", mappedBy="bookables")
95
     */
96
    private $bookableTags;
97
98
    /**
99
     * @var Collection
100
     * @ORM\OneToMany(targetEntity="Booking", mappedBy="bookable")
101
     */
102
    private $bookings;
103
104
    /**
105
     * @var Collection
106
     * @ORM\ManyToMany(targetEntity="License", mappedBy="bookables")
107
     */
108
    private $licenses;
109
110
    /**
111
     * @var null|Image
112
     * @ORM\OneToOne(targetEntity="Image", orphanRemoval=true)
113
     * @ORM\JoinColumn(name="image_id", referencedColumnName="id")
114
     */
115
    private $image;
116
117
    /**
118
     * @var null|Account
119
     *
120
     * @ORM\ManyToOne(targetEntity="Account")
121
     * @ORM\JoinColumns({
122
     *     @ORM\JoinColumn(nullable=true, onDelete="CASCADE")
123
     * })
124
     */
125
    private $creditAccount;
126
127
    /**
128
     * Constructor
129
     */
130 15
    public function __construct()
131
    {
132 15
        $this->initialPrice = Money::CHF(0);
133 15
        $this->periodicPrice = Money::CHF(0);
134 15
        $this->purchasePrice = Money::CHF(0);
135
136 15
        $this->bookings = new ArrayCollection();
137 15
        $this->licenses = new ArrayCollection();
138 15
        $this->bookableTags = new ArrayCollection();
0 ignored issues
show
Documentation Bug introduced by
It seems like new Doctrine\Common\Collections\ArrayCollection() of type Doctrine\Common\Collections\ArrayCollection is incompatible with the declared type Application\Model\BookableTag of property $bookableTags.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
139 15
    }
140
141
    /**
142
     * @return Collection
143
     */
144 2
    public function getBookings(): Collection
145
    {
146 2
        return $this->bookings;
147
    }
148
149
    /**
150
     * Notify the bookable that it has a new booking.
151
     * This should only be called by Booking::addBookable()
152
     *
153
     * @param Booking $booking
154
     */
155 11
    public function bookingAdded(Booking $booking): void
156
    {
157 11
        $this->bookings->add($booking);
158 11
    }
159
160
    /**
161
     * Notify the bookable that it a booking was removed.
162
     * This should only be called by Booking::removeBookable()
163
     *
164
     * @param Booking $booking
165
     */
166 1
    public function bookingRemoved(Booking $booking): void
167
    {
168 1
        $this->bookings->removeElement($booking);
169 1
    }
170
171
    /**
172
     * @return Collection
173
     */
174 3
    public function getLicenses(): Collection
175
    {
176 3
        return $this->licenses;
177
    }
178
179
    /**
180
     * Notify the bookable that it has a new license.
181
     * This should only be called by License::addBookable()
182
     *
183
     * @param License $license
184
     */
185 1
    public function licenseAdded(License $license): void
186
    {
187 1
        $this->licenses->add($license);
188 1
    }
189
190
    /**
191
     * Notify the bookable that it a license was removed.
192
     * This should only be called by License::removeBookable()
193
     *
194
     * @param License $license
195
     */
196 1
    public function licenseRemoved(License $license): void
197
    {
198 1
        $this->licenses->removeElement($license);
199 1
    }
200
201
    /**
202
     * @return Money
203
     */
204 6
    public function getInitialPrice(): Money
205
    {
206 6
        return $this->initialPrice;
207
    }
208
209
    /**
210
     * @param Money $initialPrice
211
     */
212 6
    public function setInitialPrice(Money $initialPrice): void
213
    {
214 6
        $this->initialPrice = $initialPrice;
215 6
    }
216
217
    /**
218
     * @return Money
219
     */
220 10
    public function getPeriodicPrice(): Money
221
    {
222 10
        return $this->periodicPrice;
223
    }
224
225
    /**
226
     * @param Money $periodicPrice
227
     */
228 8
    public function setPeriodicPrice(Money $periodicPrice): void
229
    {
230 8
        $this->periodicPrice = $periodicPrice;
231 8
    }
232
233
    /**
234
     * @return Money
235
     */
236
    public function getPurchasePrice(): Money
237
    {
238
        return $this->purchasePrice;
239
    }
240
241
    /**
242
     * @param Money $purchasePrice
243
     */
244
    public function setPurchasePrice(Money $purchasePrice): void
245
    {
246
        $this->purchasePrice = $purchasePrice;
247
    }
248
249
    /**
250
     * @return int
251
     */
252 1
    public function getSimultaneousBookingMaximum(): int
253
    {
254 1
        return $this->simultaneousBookingMaximum;
255
    }
256
257
    /**
258
     * @param int $simultaneousBookingMaximum
259
     */
260
    public function setSimultaneousBookingMaximum(int $simultaneousBookingMaximum): void
261
    {
262
        $this->simultaneousBookingMaximum = $simultaneousBookingMaximum;
263
    }
264
265
    /**
266
     * @API\Field(type="BookingType")
267
     *
268
     * @return string
269
     */
270 7
    public function getBookingType(): string
271
    {
272 7
        return $this->bookingType;
273
    }
274
275
    /**
276
     * Whether this bookable can be booked
277
     *
278
     * @return bool
279
     */
280 2
    public function isActive(): bool
281
    {
282 2
        return $this->isActive;
283
    }
284
285
    /**
286
     * Whether this bookable can be booked
287
     *
288
     * @param bool $isActive
289
     */
290
    public function setIsActive(bool $isActive): void
291
    {
292
        $this->isActive = $isActive;
293
    }
294
295
    /**
296
     * @API\Input(type="BookingType")
297
     *
298
     * @param string $state
299
     */
300 1
    public function setBookingType(string $state): void
301
    {
302 1
        $this->bookingType = $state;
303 1
    }
304
305
    /**
306
     * State of the bookable
307
     *
308
     * @API\Field(type="BookableState")
309
     *
310
     * @return string
311
     */
312
    public function getState(): string
313
    {
314
        return $this->state;
315
    }
316
317
    /**
318
     * State of the bookable
319
     *
320
     * @API\Input(type="BookableState")
321
     *
322
     * @param string $state
323
     */
324
    public function setState(string $state): void
325
    {
326
        $this->state = $state;
327
    }
328
329
    /**
330
     * The date then the bookable was last checked
331
     *
332
     * @return null|Date
333
     */
334
    public function getVerificationDate(): ?Date
335
    {
336
        return $this->verificationDate;
337
    }
338
339
    /**
340
     * The date then the bookable was last checked
341
     *
342
     * @param null|Date $verificationDate
343
     */
344
    public function setVerificationDate(?Date $verificationDate): void
345
    {
346
        $this->verificationDate = $verificationDate;
347
    }
348
349
    /**
350
     * @return Collection
351
     */
352 7
    public function getBookableTags(): Collection
353
    {
354 7
        return $this->bookableTags;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->bookableTags returns the type Application\Model\BookableTag which is incompatible with the type-hinted return Doctrine\Common\Collections\Collection.
Loading history...
355
    }
356
357
    /**
358
     * Notify the user that it has a new bookableTag.
359
     * This should only be called by BookableTag::addUser()
360
     *
361
     * @param BookableTag $bookableTag
362
     */
363 1
    public function bookableTagAdded(BookableTag $bookableTag): void
364
    {
365 1
        $this->bookableTags->add($bookableTag);
0 ignored issues
show
Bug introduced by
The method add() does not exist on Application\Model\BookableTag. ( Ignorable by Annotation )

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

365
        $this->bookableTags->/** @scrutinizer ignore-call */ 
366
                             add($bookableTag);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
366 1
    }
367
368
    /**
369
     * Notify the user that it a bookableTag was removed.
370
     * This should only be called by BookableTag::removeUser()
371
     *
372
     * @param BookableTag $bookableTag
373
     */
374
    public function bookableTagRemoved(BookableTag $bookableTag): void
375
    {
376
        $this->bookableTags->removeElement($bookableTag);
0 ignored issues
show
Bug introduced by
The method removeElement() does not exist on Application\Model\BookableTag. ( Ignorable by Annotation )

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

376
        $this->bookableTags->/** @scrutinizer ignore-call */ 
377
                             removeElement($bookableTag);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
377
    }
378
379
    /**
380
     * @return null|Image
381
     */
382 1
    public function getImage(): ?Image
383
    {
384 1
        return $this->image;
385
    }
386
387
    /**
388
     * @param null|Image $image
389
     */
390 1
    public function setImage(?Image $image): void
391
    {
392
        // We must trigger lazy loading, otherwise Doctrine will seriously
393
        // mess up lifecycle callbacks and delete unrelated image on disk
394 1
        if ($this->image) {
395 1
            $this->image->getFilename();
396
        }
397
398 1
        $this->image = $image;
399 1
    }
400
401
    /**
402
     * The account to credit when booking this bookable
403
     *
404
     * @return null|Account
405
     */
406 8
    public function getCreditAccount(): ?Account
407
    {
408 8
        return $this->creditAccount;
409
    }
410
411
    /**
412
     * The account to credit when booking this bookable
413
     *
414
     * @param null|Account $creditAccount
415
     */
416 5
    public function setCreditAccount(?Account $creditAccount): void
417
    {
418 5
        $this->creditAccount = $creditAccount;
419 5
    }
420
421
    /**
422
     * Return a list of effective active bookings including sharing conditions.
423
     *
424
     * Only "admin-only" + storage tags are sharable bookables. In this case, a list of bookings is returned.
425
     *
426
     * For other bookable types, returns null
427
     *
428
     * @return Booking[]
429
     */
430 7
    public function getSharedBookings(): array
431
    {
432 7
        $isAdminOnly = $this->getBookingType() === \Application\DBAL\Types\BookingTypeType::ADMIN_ONLY;
433
434 7
        $isStorage = false;
435 7
        foreach ($this->getBookableTags() as $tag) {
436 3
            if ($tag->getId() === BookableTagRepository::STORAGE_ID) {
437 1
                $isStorage = true;
438
439 1
                break;
440
            }
441
        }
442
443 7
        if (!$isAdminOnly || !$isStorage) {
444 7
            return [];
445
        }
446
447
        $bookings = $this->getBookings()->filter(function (Booking $booking): bool {
448 1
            return !$booking->getEndDate();
449 1
        })->toArray();
450
451 1
        return $bookings;
452
    }
453
}
454