Лучшие практики для PHP/MySQL Appointment/ Система бронирования
Мне нужно, чтобы некоторые люди боролись с "лучшей практикой" для системы встреч PHP/MySQL для парикмахера, над которым я сейчас работаю. Надеемся, что вместе мы сможем прояснить некоторые вещи, чтобы избежать необходимости повторного выполнения системы после этого. Я искал SO и Google для некоторых учебных пособий, лучших практик и т. Д., Но я не нашел ничего, что соответствует моим потребностям.
Основная информация
Каждый день работает несколько парикмахеров, у каждого парикмахера есть своя собственная повестка дня, содержащая его / ее встречи с клиентами. К парикмахерской подключен стол с указанием времени, которое он / она доступен в течение недели.
Таблица: люди
+----+------+-------+-----------+
| id | name | email | available |
+----+------+-------+-----------+
| 1 | John | i@a.c | Y |
| 2 | Sara | c@i.a | N |
+----+------+-------+-----------+
Таблица: время (есть первичный ключ для этой таблицы, я оставил его вне графика)
+-----------+-------------+-----------+-----------+
| people_id | day_of_week | start | end |
+-----------+-------------+-----------+-----------+
| 1 | 1 | 08:00 | 12:00 |
| 1 | 1 | 12:30 | 17:00 |
| 1 | 3 | 09:00 | 12:00 |
| 1 | 4 | 10:30 | 16:00 |
| 1 | 5 | 09:00 | 17:00 |
| 1 | 6 | 09:00 | 12:00 |
| 2 | 1 | 09:00 | 12:00 |
| 2 | 2 | 09:00 | 12:00 |
| 2 | 3 | 09:00 | 12:00 |
+-----------+-------------+-----------+-----------+
Как вы можете видеть, между людьми и временем существуют отношения один ко многим (очевидно, поскольку в неделе 7 дней). Но помимо этого есть также возможность добавить перерыв между часами дня (см. People_id = 1, day_of_week = 1: 08:00-12:00 и 12:30-17:00).
Кроме того, есть таблица с именем 'hairdress_types', это таблица, содержащая различные типы встреч (например, окрашивание волос, стрижка волос, мытье и т. Д.). Эта таблица содержит количество времени, которое эта встреча занимает в минутах.
Наконец-то у меня есть стол appointments
что довольно просто:
id, people_id, types_id, sex, fullname, telephone, emailaddress, date_start, date_end
Начало и конец даты будут полными полями DATETIME в MySQL, что облегчит вычисление с использованием функций запросов MySQL.
Какая лучшая практика?
Таким образом, как я настраивал, пользователь внешнего интерфейса выбирал дату в поле, запускающем функцию ajax/jquery, которая находит всех парикмахеров, доступных на выбранную дату. Затем пользователь указывает парикмахера (это не обязательно: пользователь также может выбрать вариант "Любой" для парикмахера) и тип встречи, которую он / она хочет сделать.
После отправки первой формы можно использовать следующую информацию:
- дата (день, месяц и год)
- people_id (может быть 0 для "Любой" или ID, если был выбран парикмахер)
- hairress_type (который связан с количеством минут, которое занимает встреча)
Используя эту информацию, я либо выбрал бы доступные даты от выбранного парикмахера, либо я бы зациклил всех доступных парикмахеров и их доступные даты.
Это где мой разум получает психическое расстройство! Потому что это лучший способ проверить доступные даты. То, как я думал, будет лучшим, было:
- Запросите время парикмахера для данной даты (1 за один раз)
- Запросите таблицу встреч, используя начальную дату результата запроса1 + сумму в минутах, которую занимает тип встречи (так:
SELECT * FROM appointments WHERE ((date_start >= $start AND date_start <= ($start+$time)) OR (date_end > $start AND date_end <= ($start+$time)) AND people_id = 1
) - Как только результаты не будут найдены, я предполагаю, что это место бесплатно, и это представляется пользователю как опция
Проблема с большими проблемами, с которой я сталкиваюсь, - это пункт 2. Мой ум действительно сходит с ума по этому запросу. Это полный запрос, который мне нужен, чтобы найти встречи, соответствующие определенному временному интервалу?
Спасибо за чтение и размышления!:-)
// Edit: немного больше "testdata":
Джон - понедельник - 12:00 - 17:00. Назначения: - 12:00 - 12:30 - 14:30 - 15:30
Пользователь хочет записаться на прием, который занимает 2 часа, в примере выше я бы проверил:
- Есть ли встреча с 12:00 до 14:00? Да,... перейти к следующему месту
- Есть ли встреча с 14:00 до 16:00? Да,... перейти к следующему месту
- Есть ли встреча с 16:00 до 18:00? Ошибка, недоступная после 17:00
Таким образом... может быть лучше использовать "временные блоки" из 10/15 минут. Делать чеки:
- 12:00 - 14:00
- 12:10 - 14:10
- 12:20 - 14:20 и т. Д.
Это будет найти доступное место с 12:30 до 14:30.
// Редактирование 2: возможность запроса к шагу 2
Я работал над некоторыми вещами на бумаге (стол с назначениями и возможными пустыми местами для использования). И я придумал следующее. Запись на прием невозможна в случае:
- Есть встреча с start_date между $ start и $ end
- Существует встреча с end_date между $ start и $ end
- Есть встреча с start_date <$ start и end_date> $ end
Запрос вышеупомянутого к таблице назначений вместе с people_id
приведет к тому, что ни одна строка (= свободное место) или одна / несколько строк, в этом случае место берется.
Я думаю, что лучший способ найти открытые места - это запросить у базы данных блоки X минут с интервалом запуска 10 минут. Плохая сторона этого решения заключается в том, что я буду получать по 6 запросов в час, то есть около 48 запросов на каждого парикмахера... Есть идеи, как уменьшить это количество запросов?
2 ответа
В конце концов я выбрал систему, которая генерировала временные метки для даты начала и окончания в базе данных. Во время проверки я добавил одну секунду в начало и вычел одну секунду из конца, чтобы избежать совпадения времени для встреч.
Что я в итоге делал
Очевидно, я не уверен, что это лучшая практика, но она сработала для меня. Пользователь начинает с выбора своего пола и предпочтений на день. Это отправляет запрос AJAX для получения информации о персонале и различных видах встреч (например, окрашивание волос, стрижка волос и т. Д.).
Когда все настройки выбраны (пол, дата, личность и тип), я начинаю с нескольких простых проверок: проверка даты, проверка, не является ли дата ("N") 7 (воскресенье). Если все в порядке, запускаются более важные вещи:
1) Тип встречи выбирается из базы данных, включая общее количество времени, которое занимает этот тип (30 минут, 45 минут и т. Д.). 2) Выбирается доступная личная информация (полный список людей в этот день или только один человек, если один выбран), включая их доступное время
Персона (или один человек) затем зацикливается, начиная с собственного времени старта. На данный момент у меня есть набор данных, содержащий:
$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)
Давайте возьмем эти демонстрационные данные:
$duration = 30 min
$startTime = 9.00h
$endTime = 9.30h
$personStart = 9.00h
$personEnd = 12.00h
Что я делаю здесь:
while( $endTime < $personEnd )
{
// Check the spot for availability
$startTime = $endTime;
$endTime = $startTime + $duration;
}
Очевидно, что в этом случае все упрощается. Потому что когда я проверяю наличие, а место не бесплатное. Я установил $ startTime равным последнему найденному событию и начну с него в цикле.
Пример:
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.
Проверьте наличие функции
// 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;
}
}
Поскольку я храню встречи как "С:10.00 до 11.00", я должен проверить места с 11:00:01 до 11:59:59, потому что в противном случае встреча в 11:00 будет отображаться в результатах.
В конце функции, в случае обнаружения встречи, я зацикливаю результаты и возвращаю последний конец. Это следующее начало цикла, о котором я упоминал выше.
Надеюсь, что это может помочь любому. Так же, как информация: ape_id
идентификатор "Назначенного лица", с которым он связан.
Используйте ключевое слово MySQL BETWEEN
,
SELECT * FROM mytable WHERE mydate BETWEEN start_date AND end_date;
Если вы хотите узнать, доступна ли встреча между сегодняшним днем и днем, вы можете сделать это:
$enddate = strtotime('+1 day', time());
SELECT * FROM mytable WHERE mydate BETWEEN NOW() AND {$enddate};