Лучшая практика для PHP / MySQL Назначение / Система бронирования

Мне нужно, чтобы некоторые люди сражались с «лучшей практикой» для системы назначения PHP / MySQL для парикмахера, над которым я сейчас работаю. Надеюсь, вместе мы сможем устранить некоторые вещи, чтобы избежать необходимости повторного использования системы после этого. Я искал SO и Google для некоторых учебных пособий, лучших практик и т. Д., Но я не нашел ничего, что бы соответствовало нуждам, которые у меня есть.

Основная информация

Каждый день есть несколько парикмахерских, каждый парикмахер имеет свою собственную повестку дня, содержащую его / ее встречи с клиентами. Подключенный к парикмахеру – это таблица, содержащая время, когда он / она доступен в течение недели.

Таблица: люди

+----+------+-------+-----------+ | id | name | email | available | +----+------+-------+-----------+ | 1 | John | i@ac | Y | | 2 | Sara | c@ia | 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», это таблица, содержащая различные типы назначений, которые можно сделать (например, раскрашивание волос, вырезание волос, стирка и т. Д.). Эта таблица содержит количество времени, которое занимает эта встреча за считанные минуты.

Наконец, у меня есть таблицы, которые довольно просто:

 id, people_id, types_id, sex, fullname, telephone, emailaddress, date_start, date_end 

Начало даты и дата даты были бы полными полями DATETIME в MySQL, что упростило бы вычисление с использованием функций запросов MySQL.

Какая практика?

Итак, способ, которым я устанавливал вещи, пользователь front-end выбрал бы дату в поле, запускающее функцию ajax / jquery, которая найдет всех парикмахеров, доступных в выбранную дату. Затем пользователь указывает парикмахера (это необязательно: пользователь может также выбрать вариант «Любой» парикмахер) и тип назначения, которое он / она хочет сделать.

После подачи первой формы можно использовать следующую информацию:

  1. дата (день, месяц и год)
  2. people_id (может быть 0 для «Any» или ID, если был выбран парикмахер)
  3. hairdress_type (который связан с количеством минут, которое занимает встреча)

Используя эту информацию, я либо выбрал бы доступные даты из выбранного парикмахера, либо я бы закрепил все доступные парикмахеры и их доступные даты.

Это – то, где мои умы получают психическое расстройство! Потому что лучший способ проверить доступные даты. То, как я думал, было бы лучше всего:

  1. Запросите время парикмахеров для данной даты (по одному за раз)
  2. Запросить таблицу встреч, используя начальную часть результата запроса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 )
  3. Как только результаты не будут найдены, я предполагаю, что это пятно является бесплатным, и это представлено в качестве опции для пользователя

Проблема с большими проблемами, с которой я столкнулся, – это пункт 2: мой разум действительно сходит с ума по этому запросу, это полный запрос, который мне нужен, чтобы найти встречи, соответствующие конкретному периоду времени?

Спасибо за чтение и мышление! 🙂

// Edit: немного больше "testdata":

Джон – понедельник – 12:00 – 17:00. Назначения: – 12:00 – 12:30 – 14:30 – 15:30

Пользователь хочет иметь встречу, которая занимает 2 часа, в экзамене выше я бы проверил:

  1. Есть ли встреча с 12:00 до 14:00? Да, переходите к следующему месту
  2. Есть ли встреча с 14:00 до 16:00? Да, переходите к следующему месту
  3. Есть ли встреча с 16:00 до 18:00? Ошибка, недоступная после 17:00

Таким образом .. может быть лучшим вариантом использовать «тайм-блоки» 10/15 минут. Выполнение чеков:

  1. 12:00 – 14:00
  2. 12:10 – 14:10
  3. 12:20 – 14:20 и т. Д.

Это позволит найти доступное место между 12:30 и 14:30.

// Редактировать 2: Предоставить запрос к шагу 2

Я работал над некоторыми материалами на бумаге (стол с назначением и возможными пустым местом для использования). И я придумал следующее. Назначение не может быть выполнено в случае:

  1. Встреча с start_date BETWEEN $ start и $ end
  2. Встреча с end_date BETWEEN $ start и $ end
  3. Встреча с start_date <$ start и end_date> $ end

Запрос вышеуказанного на таблицу назначения вместе с people_id приведет к people_id что ни строки (= свободная точка), ни одна / несколько строк (строк) в этом случае не будут приняты.

Я думаю, что лучший способ найти открытые места – это запросить базу данных для блоков по X минут с интервалом начала 10 минут. Плохая сторона этого решения заключается в том, что я бы выполнил 6 запросов на каждый час, что составило бы около 48 запросов для каждого парикмахера … Любые идеи о том, как уменьшить количество запросов?

В итоге я пошел на систему, которая создавала временные метки для дат начала и окончания в базе данных. При проверке я добавил одну секунду к началу и вычитал одну секунду из конца, чтобы избежать любого перекрывающегося времени для встреч.

Что я в итоге сделал

Очевидно, я не уверен, что это лучшая практика, но это сработало для меня. Пользователь начинает выбирать свой пол и предпочитает день. Это отправляет запрос AJAX для получения доступных персонажей и различных типов встреч (fe раскрашивание волос, обрезка волос и т. Д.).

Когда все настройки были выбраны (пол, дата, персонаж и тип), я начинаю с некоторых простых проверок: проверяя дату, проверяя, не является ли дата («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("Ymd H:i:s", $start)."' AND '".date("Ymd H:i:s", $end)."' OR app_end BETWEEN '".date("Ymd H:i:s", $start)."' AND '".date("Ymd H:i:s", $end)."' ) OR ( app_start < '".date("Ymd H:i:s", $start)."' AND app_end > '".date("Ymd 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}; 

Источник