No final, optei por um sistema que gerava registros de data e hora para as datas de início e término no banco de dados. Durante a verificação, adicionei um segundo ao início e subtraí um segundo do final para evitar qualquer tempo sobreposto para compromissos.
O que acabei fazendo
Obviamente, não tenho certeza de que essa seja a melhor prática, mas funcionou para mim. O usuário começa selecionando seu sexo e uma preferência para o dia. Isso envia uma solicitação AJAX para obter o pessoal disponível e vários tipos de compromissos (por exemplo, coloração de cabelo, corte de cabelo etc.).
Quando todas as configurações foram escolhidas (sexo, data, pessoal e tipo) eu começo por algumas validações simples:verificar a data, verificar se a data("N") não é 7 (domingo). Se tudo estiver bem, as coisas mais importantes são iniciadas:
1) O tipo de compromisso é buscado no banco de dados incluindo a quantidade total de tempo que este tipo leva (30 minutos, 45 minutos, etc)2) O pessoal disponível é buscado (uma lista completa de pessoas naquele dia ou apenas uma única pessoa se um é escolhido) incluindo seus horários disponíveis
O pessoal (ou uma pessoa) é então colocado em loop, começando com seu próprio horário de início. Neste ponto, tenho um conjunto de dados contendo:
$duration (of the appointment type)
$startTime (starting time of the person selected in the loop)
$endTime (= $startTime + $duration)
$personStart (= starting time of the person)
$personEnd (= end time of the person)
Vamos pegar esses dados de demonstração:
$duration = 30 min
$startTime = 9.00h
$endTime = 9.30h
$personStart = 9.00h
$personEnd = 12.00h
O que estou fazendo aqui é:
while( $endTime < $personEnd )
{
// Check the spot for availability
$startTime = $endTime;
$endTime = $startTime + $duration;
}
Obviamente, é tudo simplificado neste caso. Porque quando eu verifico a disponibilidade, e a vaga não é gratuita. Eu defino o $startTime para ser igual ao último compromisso encontrado e começo a partir daí no loop.
Exemplo:
I check for a free spot at 9.00 but the spot is not free because there's an appointment from 9.00 till 10.00, then 10.00 is returned and $startTime is set to 10.00h instead of 9.30h. This is done to keep the number of queries to a minimum since there can be quiet a lot.
Verifique a função de disponibilidade
// Check Availability
public static function checkAvailability($start, $end, $ape_id)
{
// add one second to the start to avoid results showing up on the full hour
$start += 1;
// remove one second from the end to avoid results showing up on the full hour
$end -= 1;
// $start and $end are timestamps
$getAppointments = PRegistry::getObject('db')->query("SELECT * FROM appointments WHERE
((
app_start BETWEEN '".date("Y-m-d H:i:s", $start)."' AND '".date("Y-m-d H:i:s", $end)."'
OR
app_end BETWEEN '".date("Y-m-d H:i:s", $start)."' AND '".date("Y-m-d H:i:s", $end)."'
)
OR
(
app_start < '".date("Y-m-d H:i:s", $start)."' AND app_end > '".date("Y-m-d H:i:s", $end)."'
))
AND
ape_id = ".PRegistry::getObject('db')->escape($ape_id));
if(PRegistry::getObject('db')->num_rows($getAppointments) == 0) {
return true;
} else {
$end = 0;
foreach(PRegistry::getObject('db')->fetch_array(MYSQLI_ASSOC, $getAppointments, false) as $app) {
if($app['app_end'] > $end) {
$end = $app['app_end'];
}
}
return $end;
}
}
Como estou armazenando compromissos como "De:10:00 até:11:00", tenho que verificar os horários de 11:00:01 até 11:59:59, caso contrário, o compromisso às 11:00 será exibido nos resultados.
Ao final da função, caso seja encontrado um compromisso, faço um loop nos resultados e retorno o último final. Este é o próximo início no loop que mencionei acima.
Espero que isso possa ser de alguma ajuda para qualquer um. Apenas como informação:
ape_id
é o ID da "Pessoa de Agendamento" com a qual está vinculado.