数据库中的时间段被预订 php 代码复制而不是跳过

timeslots in database are being duplicated by bookings php code instead of skipped

我正在使用 Fullcalendar 4 创建一个预订系统,供客户预订设备维修的标注时段。

到目前为止,在此处用户的帮助下,我已经设法让日历对象将预订的时段填充到日历中,而且我几乎已经使用单独的 eventSouce 将其添加到免费的未预订时段中,并且在服务器端检查 php 一天中哪些时段被占用并跳过它们。

$cDate 是 Fullcalendar 发送的请求的 DateTime 转换开始日期。

$eDate 是 Fullcalendar 发送的请求的 DateTime 转换结束日期。

$daysInRange 是一个 datediff 变量,我在页面上进一步计算它以查看 $cDate 和 $eDate 之间有多少天。

典型的url如下来自ajax请求:

getBookings.php?start=2020-06-05T00%3A00%3A00&end=2020-06-05T00%3A00%3A00&timeZone=Europe%2FLondon

$bookingStart = new DateTime( $_GET[ 'start' ] );
$bookingEnd = new DateTime( $_GET[ 'end' ] );

//Get The Start Date/Time seperately and End Date/Time Seperately.
$startdate = date_format( $bookingStart, 'Y-m-d' );
$starttime = date_format( $bookingStart, 'H:i:s' );
$enddate = date_format( $bookingEnd, 'Y-m-d' );
$endtime = date_format( $bookingEnd, 'H:i:s' );

我的php代码是:

$cDate = $bookingStart;
$eDate = $bookingEnd;
$slotBooked = true;

if ( count( $bookingResult ) > 0 ) {

       foreach ( $bookingResult as $bookingRes ) {

       //For this result we need to check each slot for the whole day and see
       //if there is a booking in any of the slots.
       ///////////////////////////////////////////////////////////////////
       //Create a variable with the bookings date and start of timeslot
       //then create one with bookings date and end time
       //Then we can see if the timeslot on the date is already booked.
       ////////////////////////////////////////////////////////////////////////

       $dbSlotStart = new DateTime( $bookingRes[ 'bookingstarttime' ] );
       $dbSlotEnd = new DateTime( $bookingRes[ 'bookingendtime' ] );
       $dbDate = new DateTime( $bookingRes[ 'bookingdate' ] );

       for ( $i = 0; $i <= $daysInRange; $i++ ) {

       //for the current slot 
        foreach ( $freeSlots as $slot ) {

            $slotStart = new DateTime( $slot[ 'start' ] );
            $slotEnd = new DateTime( $slot[ 'end' ] );

            if ( $dbDate == $cDate ) {

            //Db Date Matches The Current Date We Are Creating Slots For.
            //Next Check If The Current Slot Is Taken.
            if ( $dbSlotStart == $slotStart && $dbSlotEnd == $slotEnd ) {

            //This slot is already booked so we can skip this slot.


            } else {

            $bookingsAsJSON[ 'title' ] = 'Unbooked Timeslot';
            $bookingsAsJSON[ 'start' ] = $cDate->format( 'Y-m-d' ) . ' ' . $slotStart->format( "H:i:s" );
            $bookingsAsJSON[ 'end' ] = $cDate->format( "Y-m-d" ) . ' ' . $slotEnd->format( "H:i:s" );
            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualDate' ] = $cDate->format( "Y-m-d" );
            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualStartTime' ] = $slotStart->format( "H:i:s" );
            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualEndTime' ] = $slotEnd->format( "H:i:s" );
            $calendarEvents[] = $bookingsAsJSON;
            }


            } else {
            //Date does not match the date we are checking so slot is free.
            $bookingsAsJSON[ 'title' ] = 'Unbooked Timeslot';
            $bookingsAsJSON[ 'start' ] = $cDate->format( 'Y-m-d' ) . ' ' . $slotStart->format( "H:i:s" );
            $bookingsAsJSON[ 'end' ] = $cDate->format( "Y-m-d" ) . ' ' . $slotEnd->format( "H:i:s" );
            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualDate' ] = $cDate->format( "Y-m-d" );
            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualStartTime' ] = $slotStart->format( "H:i:s" );
            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualEndTime' ] = $slotEnd->format( "H:i:s" );
            $calendarEvents[] = $bookingsAsJSON;    
            }

        }


            //Now add 1 day to the cDate and then check if its greater than the eDate
            $cDate->modify( '+1 Day' );
            if ($cDate > $eDate) { 
            break;
            }


            }
            } 
            } else {

                for ( $i = 0; $i <= $daysInRange; $i++ ) {

                    foreach ( $freeSlots as $slot ) {

                        $slotStart = new DateTime( $slot[ 'start' ] );
                        $slotEnd = new DateTime( $slot[ 'end' ] );

                        $bookingsAsJSON[ 'title' ] = 'Unbooked Timeslot';
                        $bookingsAsJSON[ 'start' ] = $cDate->format( 'Y-m-d' ) . ' ' . $slotStart->format( "H:i:s" );
                        $bookingsAsJSON[ 'end' ] = $cDate->format( "Y-m-d" ) . ' ' . $slotEnd->format( "H:i:s" );
                        $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualDate' ] = $cDate->format( "Y-m-d" );
                        $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualStartTime' ] = $slotStart->format( "H:i:s" );
                            $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualEndTime' ] = $slotEnd->format( "H:i:s" );
                            $calendarEvents[] = $bookingsAsJSON;
              }  


        //Now add 1 day to the cDate and then check if its greater than the eDate
                $cDate->modify( '+1 Day' );
                if ($cDate > $eDate) { 

                break;
                }
            }


            }

上面的代码可以工作,但是例如,如果在 09:00:00 - 11:00:00 的 2020-06-05 上有一个时段,范围是 2020-06-01 到 2020 -06-08 然后我在 5 号上午 9 点到上午 11 点获得预订的时段,红色为预订,绿色为免费。

我不确定我为什么会收到这个..

正如您在 6 月 5 日上午 9 点到晚上 11 点从上面的屏幕截图中看到的那样,有一个已预订的红色插槽,同样的插槽再次以绿色显示为免费....

任何关于我在代码中出错的地方的帮助都会很棒 :)

编辑

此处要求的是 $bookingRes 的输出:

array (
  0 => 
  array (
    'assetjobid' => '11',
    0 => '11',
    'companyid' => 'CADB-UK-0001',
    1 => 'CADB-UK-0001',
    'assetid' => '82',
    2 => '82',
    'job_createdby' => 'Administrator',
    3 => 'Administrator',
    'job_createdate' => '2020-05-16',
    4 => '2020-05-16',
    'job_duedate' => '2020-06-01',
    5 => '2020-06-01',
    'job_status' => '1',
    6 => '1',
    'job_priority' => '1',
    7 => '1',
    'job_type' => '1',
    8 => '1',
    'job_assignedto' => 'Garry Law',
    9 => 'Garry Law',
    'job_completedate' => NULL,
    10 => NULL,
    'job_notes' => NULL,
    11 => NULL,
    'booking_id' => '9',
    12 => '9',
    'bookingstarttime' => '11:00:00',
    13 => '11:00:00',
    'bookingendtime' => '13:00:00',
    14 => '13:00:00',
    'bookingdate' => '2020-06-01',
    15 => '2020-06-01',
    'asset_jobid' => '11',
    16 => '11',
    17 => '1',
    'engineer_id' => '1',
    18 => '1',
    'bookingstatus' => '1',
    19 => '1',
    'invoice_item_id' => '9',
    20 => '9',
    'company_id' => '1',
    21 => '1',
    22 => 'CADB-UK-0001',
    'companyname' => 'Example Company',
    23 => 'Example Company',
    'companyaddress1' => 'Example House',
    24 => 'Example House',
    'companyaddress2' => 'Example Street',
    25 => 'Example Street',
    'companyaddresscity' => 'Example City',
    26 => 'Example City',
    'companyaddresspostcode' => 'EX1 C12',
    27 => 'EX1 C12',
    'companytelephone' => '01234 567 890',
    28 => '01234 567 890',
    'companysector' => 'Example Sector',
    29 => 'Example Sector',
    'billingid' => '1',
    30 => '1',
    'company_contactname' => 'Mr Example Contact',
    31 => 'Mr Example Contact',
    'company_contactposition' => 'Head Of IT',
    32 => 'Head Of IT',
    'asset_id' => '11',
    33 => '11',
    'assetcompanyid' => 'CADB-UK-0001',
    34 => 'CADB-UK-0001',
    'assetname' => 'HP 280 G3',
    35 => 'HP 280 G3',
    'assettype' => '2',
    36 => '2',
    'assetmodel' => '280 G3',
    37 => '280 G3',
    'assetmake' => 'HP',
    38 => 'HP',
    'assetlocation' => '4',
    39 => '4',
    'assetstatus' => '1',
    40 => '1',
    'assetlastcheck' => '2020-01-14 00:00:00',
    41 => '2020-01-14 00:00:00',
    'assetSerialNumber' => NULL,
    42 => NULL,
    'assettag' => 'TESTCOMPANY-PC4',
    43 => 'TESTCOMPANY-PC4',
    'assetpurchasedate' => '2019-08-06 00:00:00',
    44 => '2019-08-06 00:00:00',
    'locationid' => '4',
    45 => '4',
    46 => 'CADB-UK-0001',
    'location_name' => 'Head Office',
    47 => 'Head Office',
    'location_room' => 'Marketing',
    48 => 'Marketing',
    'location_notes' => NULL,
    49 => NULL,
  ),
  1 => 
  array (
    'assetjobid' => '12',
    0 => '12',
    'companyid' => 'CADB-UK-0001',
    1 => 'CADB-UK-0001',
    'assetid' => '77',
    2 => '77',
    'job_createdby' => 'Administrator',
    3 => 'Administrator',
    'job_createdate' => '2020-05-15',
    4 => '2020-05-15',
    'job_duedate' => '2020-06-03',
    5 => '2020-06-03',
    'job_status' => '1',
    6 => '1',
    'job_priority' => '1',
    7 => '1',
    'job_type' => '1',
    8 => '1',
    'job_assignedto' => 'Garry Law',
    9 => 'Garry Law',
    'job_completedate' => NULL,
    10 => NULL,
    'job_notes' => NULL,
    11 => NULL,
    'booking_id' => '10',
    12 => '10',
    'bookingstarttime' => '13:00:00',
    13 => '13:00:00',
    'bookingendtime' => '15:00:00',
    14 => '15:00:00',
    'bookingdate' => '2020-06-03',
    15 => '2020-06-03',
    'asset_jobid' => '12',
    16 => '12',
    17 => '1',
    'engineer_id' => '1',
    18 => '1',
    'bookingstatus' => '1',
    19 => '1',
    'invoice_item_id' => '10',
    20 => '10',
    'company_id' => '1',
    21 => '1',
    22 => 'CADB-UK-0001',
    'companyname' => 'Example Company',
    23 => 'Example Company',
    'companyaddress1' => 'Example House',
    24 => 'Example House',
    'companyaddress2' => 'Example Street',
    25 => 'Example Street',
    'companyaddresscity' => 'Example City',
    26 => 'Example City',
    'companyaddresspostcode' => 'EX1 C12',
    27 => 'EX1 C12',
    'companytelephone' => '01234 567 890',
    28 => '01234 567 890',
    'companysector' => 'Example Sector',
    29 => 'Example Sector',
    'billingid' => '1',
    30 => '1',
    'company_contactname' => 'Mr Example Contact',
    31 => 'Mr Example Contact',
    'company_contactposition' => 'Head Of IT',
    32 => 'Head Of IT',
    'asset_id' => '12',
    33 => '12',
    'assetcompanyid' => 'CADB-UK-0001',
    34 => 'CADB-UK-0001',
    'assetname' => 'HP 280 G3',
    35 => 'HP 280 G3',
    'assettype' => '2',
    36 => '2',
    'assetmodel' => '280 G3',
    37 => '280 G3',
    'assetmake' => 'HP',
    38 => 'HP',
    'assetlocation' => '5',
    39 => '5',
    'assetstatus' => '1',
    40 => '1',
    'assetlastcheck' => '2020-01-14 00:00:00',
    41 => '2020-01-14 00:00:00',
    'assetSerialNumber' => NULL,
    42 => NULL,
    'assettag' => 'TESTCOMPANY-PC5',
    43 => 'TESTCOMPANY-PC5',
    'assetpurchasedate' => '2019-08-06 00:00:00',
    44 => '2019-08-06 00:00:00',
    'locationid' => '5',
    45 => '5',
    46 => 'CADB-UK-0001',
    'location_name' => 'Head Office',
    47 => 'Head Office',
    'location_room' => 'Sales',
    48 => 'Sales',
    'location_notes' => NULL,
    49 => NULL,
  ),
  2 => 
  array (
    'assetjobid' => '13',
    0 => '13',
    'companyid' => 'CADB-UK-0001',
    1 => 'CADB-UK-0001',
    'assetid' => '110',
    2 => '110',
    'job_createdby' => 'Administrator',
    3 => 'Administrator',
    'job_createdate' => '2020-05-01',
    4 => '2020-05-01',
    'job_duedate' => '2020-06-05',
    5 => '2020-06-05',
    'job_status' => '1',
    6 => '1',
    'job_priority' => '2',
    7 => '2',
    'job_type' => '1',
    8 => '1',
    'job_assignedto' => 'Garry Law',
    9 => 'Garry Law',
    'job_completedate' => NULL,
    10 => NULL,
    'job_notes' => NULL,
    11 => NULL,
    'booking_id' => '11',
    12 => '11',
    'bookingstarttime' => '09:00:00',
    13 => '09:00:00',
    'bookingendtime' => '11:00:00',
    14 => '11:00:00',
    'bookingdate' => '2020-06-05',
    15 => '2020-06-05',
    'asset_jobid' => '13',
    16 => '13',
    17 => '1',
    'engineer_id' => '1',
    18 => '1',
    'bookingstatus' => '1',
    19 => '1',
    'invoice_item_id' => '11',
    20 => '11',
    'company_id' => '1',
    21 => '1',
    22 => 'CADB-UK-0001',
    'companyname' => 'Example Company',
    23 => 'Example Company',
    'companyaddress1' => 'Example House',
    24 => 'Example House',
    'companyaddress2' => 'Example Street',
    25 => 'Example Street',
    'companyaddresscity' => 'Example City',
    26 => 'Example City',
    'companyaddresspostcode' => 'EX1 C12',
    27 => 'EX1 C12',
    'companytelephone' => '01234 567 890',
    28 => '01234 567 890',
    'companysector' => 'Example Sector',
    29 => 'Example Sector',
    'billingid' => '1',
    30 => '1',
    'company_contactname' => 'Mr Example Contact',
    31 => 'Mr Example Contact',
    'company_contactposition' => 'Head Of IT',
    32 => 'Head Of IT',
    'asset_id' => '13',
    33 => '13',
    'assetcompanyid' => 'CADB-UK-0001',
    34 => 'CADB-UK-0001',
    'assetname' => 'HP 280 G3',
    35 => 'HP 280 G3',
    'assettype' => '2',
    36 => '2',
    'assetmodel' => '280 G3',
    37 => '280 G3',
    'assetmake' => 'HP',
    38 => 'HP',
    'assetlocation' => '5',
    39 => '5',
    'assetstatus' => '1',
    40 => '1',
    'assetlastcheck' => '2020-01-14 00:00:00',
    41 => '2020-01-14 00:00:00',
    'assetSerialNumber' => NULL,
    42 => NULL,
    'assettag' => 'TESTCOMPANY-PC6',
    43 => 'TESTCOMPANY-PC6',
    'assetpurchasedate' => '2019-08-06 00:00:00',
    44 => '2019-08-06 00:00:00',
    'locationid' => '5',
    45 => '5',
    46 => 'CADB-UK-0001',
    'location_name' => 'Head Office',
    47 => 'Head Office',
    'location_room' => 'Sales',
    48 => 'Sales',
    'location_notes' => NULL,
    49 => NULL,
  )

$bookingRes 是 PDO 查询的输出,它在 FullCalendar 请求的日期范围内获取预订时段的记录。

进一步编辑

如果您还可以看到 $freeSlots 的组成部分,我认为它可能会有用:

      array (
  1 => 
  array (
    'start' => '09:00',
    'end' => '11:00',
  ),
  2 => 
  array (
    'start' => '11:00',
    'end' => '13:00',
  ),
  3 => 
  array (
    'start' => '13:00',
    'end' => '15:00',
  ),
  4 => 
  array (
    'start' => '15:00',
    'end' => '17:00',
  ),
)

感谢@ADyson 帮助我解决了使用 FullCalendar 时遇到的问题。

不过,我已经完成了我需要做的任务。

我处理它的方式是:

  1. 在 1 天内创建可用插槽数组。

  2. 在请求的日期范围内创建一个新的可用广告位数组,创建一个新的 包含 datestartendisbooked[=41= 字段的数组].

    现在我有一个数组,其中包含整个请求日期范围内的槽时间和日期,我面临的最后一个问题是如何在 foreach 循环中完成它并更改原始值?我偶然发现了 Whosebug 上的另一个答案,它为我回答了这个问题,因此,我能够在最终数组上执行最终的 foreach 循环,并遍历每个数据库结果以检查它是否与 foreach 显示的时间段上的日期匹配然后将 isbooked 标志设置为 true。

终于!我有一组工作代码创建了我需要的 JSON return。没有重复,只有免费插槽和预订插槽很好地坐在一起。

我得到的最终代码如下:

    for ( $i = 0; $i <= $daysInRange; $i++ ) {

    //for the current date we need to go through each slot. 
    foreach ( $freeSlots as $slot ) {

        $slotStart = new DateTime( $slot[ 'start' ] );
        $slotEnd = new DateTime( $slot[ 'end' ] );



                $aSlot[ 'date' ] = $cDate->format( "Y-m-d" );
                $aSlot[ 'start' ] = $slotStart->format( "H:i:s" );
                $aSlot[ 'end' ] = $slotEnd->format( "H:i:s" );
                $aSlot[ 'isbooked' ] = false;
                $allSlots[] = $aSlot;   


    }



    //Now add 1 day to the cDate and then check if its greater than the eDate
    $cDate->modify( '+1 Day' );
    if ( $cDate > $eDate ) {
        break;
    }

}
//var_export($allSlots);
#check new array against database and mark booked slots 
foreach($allSlots as &$slot){

    foreach($bookingResult as $booking) {

        if($booking['bookingdate'] == $slot['date'] && $booking['bookingstarttime'] == $slot['start'] && $booking['bookingendtime'] == $slot['end']){
            $slot['isbooked'] = true;
        }

    }

}
//Now booked slots are marked we can now create the JSON.
foreach ( $allSlots as $slot ) {

    $slotStart = new DateTime( $slot[ 'start' ] );
    $slotEnd = new DateTime( $slot[ 'end' ] );
    $slotDate = new DateTime( $slot[ 'date' ] );


    if ( $slot[ 'isbooked' ] == false ) {
        $bookingsAsJSON[ 'title' ] = 'Unbooked Timeslot';
        $bookingsAsJSON[ 'start' ] = $slotDate->format("Y-m-d"). ' ' . $slotStart->format( "H:i:s" );
        $bookingsAsJSON[ 'end' ] = $slotDate->format( "Y-m-d" ) . ' ' . $slotEnd->format( "H:i:s" );
        $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualDate' ] = $slotDate->format( "Y-m-d" );
        $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualStartTime' ] = $slotStart->format( "H:i:s" );
        $bookingsAsJSON[ 'extendedProps' ][ 'bookingActualEndTime' ] = $slotEnd->format( "H:i:s" );
        $calendarEvents[] = $bookingsAsJSON;
    }
}

日历上的输出如下所示: