Completed
Push — master ( cb5fa1...8201f5 )
by Vojta
06:45
created

ReservationsFacade::isUserReturning()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6.0131

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 13
cts 14
cp 0.9286
rs 8.439
c 0
b 0
f 0
cc 6
eloc 15
nc 9
nop 1
crap 6.0131
1
<?php namespace VojtaSvoboda\Reservations\Facades;
2
3
use Auth;
4
use Carbon\Carbon;
5
use Config;
6
use Event;
7
use Illuminate\Database\Eloquent\Collection;
8
use Illuminate\Support\Facades\DB;
9
use October\Rain\Exception\ApplicationException;
10
use October\Rain\Exception\ValidationException;
11
use VojtaSvoboda\Reservations\Classes\DatesResolver;
12
use VojtaSvoboda\Reservations\Mailers\ReservationMailer;
13
use VojtaSvoboda\Reservations\Models\Reservation;
14
use VojtaSvoboda\Reservations\Models\Settings;
15
use VojtaSvoboda\Reservations\Models\Status;
16
17
/**
18
 * Public reservations facade.
19
 *
20
 * Usage: App::make('vojtasvoboda.reservations.facade');
21
 *
22
 * @package VojtaSvoboda\Reservations\Facades
23
 */
24
class ReservationsFacade
25
{
26
    /** @var Reservation $reservations */
27
    private $reservations;
28
29
    /** @var Status $statuses */
30
    private $statuses;
31
32
    /** @var DatesResolver $datesResolver */
33
    private $datesResolver;
34
35
    /** @var array $returningUsersCache */
36
    private $returningUsersCache;
37
38
    /**
39
     * ReservationsFacade constructor.
40
     *
41
     * @param Reservation $reservations
42
     * @param Status $statuses
43
     * @param DatesResolver $resolver
44
     */
45 9
    public function __construct(Reservation $reservations, Status $statuses, DatesResolver $resolver)
46
    {
47 9
        $this->reservations = $reservations;
48 9
        $this->statuses = $statuses;
49 9
        $this->datesResolver = $resolver;
50 9
    }
51
52
    /**
53
     * Create and store reservation.
54
     *
55
     * @param array $data
56
     *
57
     * @return Reservation $reservation
58
     *
59
     * @throws ApplicationException
60
     * @throws ValidationException
61
     */
62 8
    public function storeReservation($data)
63
    {
64
        // transform date and time to Carbon
65 8
        $data['date'] = $this->transformDateTime($data);
66
67
        // check date availability
68 6
        $this->checkDate($data);
69
70
        // create reservation
71 6
        $reservation = $this->reservations->create($data);
72
73
        // send reservation confirmation
74 6
        ReservationMailer::send($reservation);
75
76 6
        return $reservation;
77
    }
78
79
    /**
80
     * Get all reservations.
81
     *
82
     * @return Collection
83
     */
84
    public function getReservations()
85
    {
86
        return $this->reservations->all();
87
    }
88
89
    /**
90
     * Get all active (not cancelled) reservations.
91
     *
92
     * @return Collection
93
     */
94
    public function getActiveReservations()
95
    {
96
        return $this->reservations->notCancelled()->get();
97
    }
98
99
    /**
100
     * Get all reserved time slots.
101
     *
102
     * @return array
103
     */
104
    public function getReservedDates()
105
    {
106
        $reservations = $this->getActiveReservations();
107
108
        return $this->datesResolver->getDatesFromReservations($reservations);
109
    }
110
111
    /**
112
     * Get all reservations by given date interval.
113
     *
114
     * @param Carbon $since Date from.
115
     * @param Carbon $till Date to.
116
     *
117
     * @return mixed
118
     */
119
    public function getReservationsByInterval(Carbon $since, Carbon $till)
120
    {
121
        return $this->reservations->whereBetween('date', [$since, $till])->get();
122
    }
123
124
    /**
125
     * Get reservations count by one email.
126
     *
127
     * @param $email
128
     *
129
     * @return int
130
     */
131 1
    public function getReservationsWithSameEmailCount($email)
132
    {
133 1
        return $this->reservations->where('email', $email)->notCancelled()->count();
134
    }
135
136
    /**
137
     * Is user returning or not? You have to set this parameter at Backend Reservations setting.
138
     *
139
     * @param $email
140
     *
141
     * @return bool
142
     */
143 1
    public function isUserReturning($email)
144
    {
145
        // if disabled, return always false
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
146 1
        $threshold = Settings::get('returning_mark', 0);
147 1
        if ($threshold < 1) {
148
            return false;
149
        }
150
151
        // load emails count
152 1
        if ($this->returningUsersCache === null) {
153
            $items = $this
154 1
                ->reservations
155 1
                ->select(DB::raw('email, count(*) as count'))
156 1
                ->groupBy('email')
157 1
                ->get();
158
            // refactor to mapWithKeys after upgrade to Laravel 5.3.
159 1
            foreach($items as $item) {
160 1
                $this->returningUsersCache[$item['email']] = $item['count'];
161
            }
162
        }
163
164 1
        $returning = $this->returningUsersCache;
165 1
        $actual = isset($returning[$email]) ? $returning[$email] : 0;
166
167 1
        return $threshold > 0 && $actual >= $threshold;
168
    }
169
170
    /**
171
     * Bulk reservation state change.
172
     *
173
     * @param array $ids
174
     * @param string $ident
175
     */
176
    public function bulkStateChange($ids, $ident)
177
    {
178
        // get state
179
        $status = $this->statuses->where('ident', $ident)->first();
180
        if (!$status) {
181
            return;
182
        }
183
184
        // go through reservations
185
        foreach ($ids as $id)
186
        {
187
            $reservation = $this->reservations->find($id);
188
            if (!$reservation) {
189
                continue;
190
            }
191
192
            $reservation->status = $status;
193
            $reservation->save();
194
        }
195
    }
196
197
    /**
198
     * Bulk reservations delete.
199
     *
200
     * @param array $ids
201
     */
202
    public function bulkDelete($ids)
203
    {
204
        // go through reservations
205
        foreach ($ids as $id)
206
        {
207
            $reservation = $this->reservations->find($id);
208
            if (!$reservation) {
209
                continue;
210
            }
211
212
            $reservation->delete();
213
        }
214
    }
215
216
    /**
217
     * Transform date and time to DateTime string.
218
     *
219
     * @param $data
220
     *
221
     * @return Carbon
222
     *
223
     * @throws ApplicationException
224
     */
225 9
    public function transformDateTime($data)
226
    {
227
        // validate date and time
228 9
        if (empty($data['date'])) {
229 1
            throw new ApplicationException('You have to select pickup date!');
230
231 8
        } elseif (empty($data['time'])) {
232 1
            throw new ApplicationException('You have to select pickup hour!');
233
        }
234
235 7
        $format = Config::get('vojtasvoboda.reservations::config.formats.datetime', 'd/m/Y H:i');
236
237 7
        return Carbon::createFromFormat($format, trim($data['date'] . ' ' . $data['time']));
238
    }
239
240
    /**
241
     * Check gived date and time.
242
     *
243
     * @param array $data
244
     *
245
     * @throws ApplicationException
246
     */
247 6
    public function checkDate($data)
248
    {
249
        // check reservation sent limit
250 6
        if ($this->isSomeReservationExistsInLastTime()) {
251
            throw new ApplicationException('You can sent only one reservation per 30 seconds, please wait a second.');
252
        }
253
254
        // check date availability
255 6
        if (!$this->isDateAvailable($data['date'])) {
256 1
            throw new ApplicationException($data['date']->format('d.m.Y H:i') . ' is already booked.');
257
        }
258 6
    }
259
260
    /**
261
     * Returns if date is available to book.
262
     *
263
     * @param Carbon $date
264
     *
265
     * @return bool
266
     */
267 6
    public function isDateAvailable(Carbon $date)
268
    {
269
        // get config
270 6
        $length = Config::get('vojtasvoboda.reservations::config.reservation.length', '2 hours');
271
272
        // check time slot before
273 6
        $startDatetime = clone $date;
274 6
        $startDatetime->modify('-' . $length);
275 6
        $startDatetime->modify('+1 second');
276
277
        // check time slot after
278 6
        $endDatetime = clone $date;
279 6
        $endDatetime->modify('+' . $length);
280 6
        $endDatetime->modify('-1 second');
281
282
        // get all reservations in this date
283 6
        $reservations = $this->reservations->notCancelled()->whereBetween('date', [$startDatetime, $endDatetime])->get();
284
285 6
        return $reservations->count() == 0;
286
    }
287
288
    /**
289
     * Try to find some reservation in less then half minute.
290
     *
291
     * @return boolean
292
     */
293 6
    public function isSomeReservationExistsInLastTime()
294
    {
295 6
        return $this->reservations->isExistInLastTime();
296
    }
297
}
298