Passed
Push — master ( 1402e3...740cbb )
by Vinicius Lourenço
03:23
created

Scheduler   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 27
eloc 57
dl 0
loc 193
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A hasScheduleBetween() 0 11 2
A validateSchedule() 0 18 6
A isShouldntAdd() 0 3 2
A availableToday() 0 3 1
B availableOn() 0 40 8
A parseToSchedule() 0 6 2
A parseToCarbon() 0 12 5
A __construct() 0 3 1
1
<?php namespace H4ad\Scheduler;
2
3
/**
4
 * Esse arquivo faz parte do Scheduler,
5
 * uma biblioteca para auxiliar com agendamentos.
6
 *
7
 * @license MIT
8
 * @package H4ad\Scheduler
9
 */
10
11
use Carbon\Carbon;
12
use H4ad\Scheduler\Models\Schedule;
13
use Illuminate\Support\Facades\Config;
14
use H4ad\Scheduler\Exceptions\CantAddWithoutEnd;
15
use H4ad\Scheduler\Exceptions\IntInvalidArgument;
16
use H4ad\Scheduler\Exceptions\EndCantBeforeStart;
17
use H4ad\Scheduler\Exceptions\CantAddWithSameStartAt;
18
19
class Scheduler
20
{
21
    /**
22
     * Laravel application
23
     *
24
     * @var \Illuminate\Foundation\Application
25
     */
26
    public $app;
27
28
    /**
29
     * Create a new confide instance.
30
     *
31
     * @param \Illuminate\Foundation\Application $app
32
     *
33
     * @return void
34
     */
35
    public function __construct($app)
36
    {
37
        $this->app = $app;
38
    }
39
40
    /**
41
     * Escopo de uma consulta que busca horarios pela data de início.
42
     *
43
     * @param string $model_type
44
     * @param string|\Carbon\Carbon $start_at
45
     * @param string|\Carbon\Carbon $end_at
46
     * @return bool
47
     */
48
    public function hasScheduleBetween($model_type, $start_at, $end_at)
49
    {
50
        if(!Config::get('scheduler.enable_schedule_conflict'))
51
            return false;
52
53
        return !is_null(
54
            Schedule::latest()
55
                ->where('model_type', $model_type)
56
                ->where('start_at', '>=', $start_at)
57
                ->where('end_at', '<=', $end_at)
58
                ->first()
59
        );
60
    }
61
62
    /**
63
     * Retorna os horários disponiveis hoje para uma determinada model.
64
     * .
65
     * @param  string  $model_type Tipo da model
66
     * @param  int    $duration Serve para facilitar na hora de buscar horários livres
67
     *                          que precisem ter uma certa duração.
68
     * @param \Carbon\Carbon|null $openingTime Serve como referencia para buscar horários livres.
69
     *                                         Se for nulo, ele busca a referencia da config.
70
     * @return array
71
     */
72
    public function availableToday($model_type, $duration, $openingTime = null)
73
    {
74
        return $this->availableOn($model_type, Carbon::now(), $duration, $openingTime);
75
    }
76
77
    /**
78
     * Retorna os horários disponiveis em um determinado dia para uma certa model.
79
     *
80
     * @param  string  $model_type Tipo da model
81
     * @param  \Carbon\Carbon $today Data para o qual ele irá fazer a busca.
82
     * @param  int    $durationMinutes Serve para facilitar na hora de buscar horários livres
83
     *                          que precisem ter uma certa duração.
84
     * @param \Carbon\Carbon|null $openingTime Serve como referencia para buscar horários livres.
85
     *                                         Se for nulo, ele busca a referencia da config.
86
     * @return array
87
     */
88
    public function availableOn($model_type, $today, $durationMinutes, $openingTime = null)
89
    {
90
        $openingTime = $openingTime ?? Carbon::parse(Config::get('scheduler.opening_time'))->setDateFrom($today);
91
        $closingTime = Carbon::parse(Config::get('scheduler.closing_time'))->setDateFrom($today);
92
93
        $livres = [];
94
        $today = Carbon::parse($today->toDateString());
95
        while($openingTime <= $closingTime)
96
        {
97
            $add = true;
98
99
            $opening = Carbon::parse($openingTime->toDateTimeString());
100
            $closing = Carbon::parse($openingTime->toDateTimeString())->addMinutes($durationMinutes);
101
102
            foreach (Schedule::where('model_type', $model_type)->orderBy('start_at', 'DESC')->cursor() as $schedule) {
103
                $start = Carbon::parse($schedule->start_at);
104
                $begin = Carbon::parse($start->toDateString());
105
106
                if($begin->greaterThan($today))
107
                    break;
108
109
                if($begin->notEqualTo($today))
110
                    continue;
111
112
                $end = Carbon::parse($schedule->end_at);
113
114
                if($this->isShouldntAdd($opening, $closing, $start, $end))
115
                    $add = false;
116
            }
117
118
            if($add && $closing->lessThanOrEqualTo($closingTime))
119
                $livres[] = [
120
                    'start_at' => $opening,
121
                    'end_at' => $closing
122
                ];
123
124
            $openingTime->addMinutes($durationMinutes);
125
        }
126
127
        return $livres;
128
    }
129
130
    /**
131
     * Verifica se ele não deve ser adicionado ao array de horários livres.
132
     *
133
     * @param  \Carbon\Carbon  $opening
134
     * @param  \Carbon\Carbon  $closing
135
     * @param  \Carbon\Carbon  $start
136
     * @param  \Carbon\Carbon  $end
137
     * @return boolean
138
     */
139
    private function isShouldntAdd($opening, $closing, $start, $end)
140
    {
141
        return $start <= $opening && $end >= $closing;
142
    }
143
144
    /**
145
     * Valida e retorna os dados formatados de forma correta em um [array].
146
     *
147
     * @param  \Carbon\Carbon|string $start_at  Data em que será agendado, pode ser em string ou em numa classe Carbon.
148
     * @param  \Carbon\Carbon|string|int|null $end_at   Data em que acabada esse agendamento, pode ser em string, ou numa classe Carbon
149
     *                                                  ou em int(sendo considerado os minutos de duração).
150
     * @param  int|null $status Status desse horário ao ser agendado.
151
     * @return array
152
     *
153
     * @throws \H4ad\Scheduler\Exceptions\CantAddWithoutEnd
154
     * @throws \H4ad\Scheduler\Exceptions\EndCantBeforeStart
155
     * @throws \H4ad\Scheduler\Exceptions\CantAddWithSameStartAt
156
     */
157
    public function validateSchedule($model_type, $start_at, $end_at = null, $status = null)
158
    {
159
        if(!Config::get('scheduler.enable_schedule_without_end') && is_null($end_at))
160
            throw new CantAddWithoutEnd;
161
162
        $start_at  = $this->parseToCarbon($start_at);
163
164
        if(!is_null($end_at)) {
165
            $end_at = $this->parseToCarbon($end_at, $start_at);
166
167
            if($start_at->greaterThan($end_at))
168
                throw new EndCantBeforeStart;
169
        }
170
171
        if($this->hasScheduleBetween($model_type, $start_at, $end_at ?? $start_at))
172
            throw new CantAddWithSameStartAt;
173
174
        return compact('model_type', 'start_at', 'end_at', 'status');
175
    }
176
177
    /**
178
     * Faz um parse na data e retorna uma instância em Carbon.
179
     *
180
     * @param  \Carbon\Carbon|string|int $date Data final que será transformada numa instancia Carbon.
181
     * @param  \Carbon\Carbon $reference Data de referencia quando o [date] é inteiro.
182
     * @return \Carbon\Carbon
183
     *
184
     * @throws \H4ad\Scheduler\Exceptions\IntInvalidArgument
185
     */
186
    public function parseToCarbon($date, $reference = null)
187
    {
188
        if($date instanceof Carbon)
189
            return $date;
190
191
        if(is_string($date))
192
            return Carbon::parse($date);
193
194
        if(is_int($date) && !is_null($reference))
195
            return Carbon::parse($reference->toDateTimeString())->addMinutes($date);
196
197
        throw new IntInvalidArgument;
198
    }
199
200
    /**
201
     * Faz um parse e retorna um Schedule.
202
     *
203
     * @param  \Carbon\Carbon|string|int $value Valor que representará a data ou o id a ser buscado.
204
     * @return \H4ad\Scheduler\Models\Schedule|null
205
     */
206
    public function parseToSchedule($value)
207
    {
208
        if(is_int($value))
209
            return Schedule::find($value);
210
211
        return Schedule::byStartAt($value)->first();
212
    }
213
}