Uname: Linux webm005.cluster107.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64
User: 6036 (villadal)
Group: 100 (users)
Disabled functions: NONE
Safe mode: On[ PHPinfo ]
//home/villadal/www/old/////booked/lib/Application/Schedule      ( Reset | Go to )
File Name: ScheduleReservationList.php
Edit
<?php
/**
Copyright 2011-2014 Nick Korbel

This file is part of Booked SchedulerBooked SchedulereIt is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later versBooked SchedulerduleIt is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
alBooked SchedulercheduleIt.  If not, see <http://www.gnu.org/licenses/>.
 */

interface IScheduleReservationList
{
    
/**
     * @return array|IReservationSlot[]
     */
    
function BuildSlots();
}

class 
ScheduleReservationList implements IScheduleReservationList
{
    
/**
     * @var array|ReservationListItem[]
     */
    
private $_items;

    
/**
     * @var IScheduleLayout
     */
    
private $_layout;

    
/**
     * @var Date
     */
    
private $_layoutDateStart;

    
/**
     * @var Date
     */
    
private $_layoutDateEnd;

    
/**
     * @var array|SchedulePeriod[]
     */
    
private $_layoutItems;

    private 
$_itemsByStartTime = array();

    
/**
     * @var array|SchedulePeriod[]
     */
    
private $_layoutByStartTime = array();

    
/**
     * @var array|int[]
     */
    
private $_layoutIndexByEndTime = array();

    
/**
     * @var Time
     */
    
private $_midnight;

    
/**
     * @var string
     */
    
private $_destinationTimezone;

    
/**
     * @var Date
     */
    
private $_firstLayoutTime;

    
/**
     * @var Date
     */
    
private $_lastLayoutTime;

    
/**
     * @param array|ReservationListItem[] $items
     * @param IScheduleLayout $layout
     * @param Date $layoutDate
     * @param bool $hideBlockedPeriods
     */
    
public function __construct($itemsIScheduleLayout $layoutDate $layoutDate$hideBlockedPeriods false)
    {
        
$this->_items $items;
        
$this->_layout $layout;
        
$this->_destinationTimezone $this->_layout->Timezone();
        
$this->_layoutDateStart $layoutDate->ToTimezone($this->_destinationTimezone)->GetDate();
        
$this->_layoutDateEnd $this->_layoutDateStart->AddDays(1);
        
$this->_layoutItems $this->_layout->GetLayout($layoutDate$hideBlockedPeriods);
        
$this->_midnight = new Time(000$this->_destinationTimezone);

        
$this->IndexLayout();
        
$this->IndexItems();
    }

    public function 
BuildSlots()
    {
        
$sw StopWatch::StartNew();

        
$slots = array();

        for (
$currentIndex 0$currentIndex count($this->_layoutItems); $currentIndex++)
        {
            
$layoutItem $this->_layoutItems[$currentIndex];
            
$item $this->GetItemStartingAt($layoutItem->BeginDate());

            if (
$item != null)
            {
                if (
$this->ItemEndsOnFutureDate($item))
                {
                    
$endTime $this->_layoutDateEnd;
                }
                else
                {
                    
$endTime $item->EndDate()->ToTimezone($this->_destinationTimezone);
                }

                
$endingPeriodIndex max($this->GetLayoutIndexEndingAt($endTime), $currentIndex);
                
$span = ($endingPeriodIndex $currentIndex) + 1;

                
$slots[] = $item->BuildSlot($layoutItem$this->_layoutItems[$endingPeriodIndex],
                                            
$this->_layoutDateStart$span);

                
$currentIndex $endingPeriodIndex;
            }
            else
            {
                
$slots[] = new EmptyReservationSlot($layoutItem$layoutItem$this->_layoutDateStart$layoutItem->IsReservable());
            }
        }

        
$sw->Stop();
//        Log::Debug('BuildSlots() took %s seconds', $sw->GetTotalSeconds());

        
return $slots;
    }

    private function 
IndexItems()
    {
        
$sw StopWatch::StartNew();

        foreach (
$this->_items as $index => $item)
        {
            if (
$item->HasBufferTime())
            {
                
$bufferItem = new BufferItem($itemBufferItem::LOCATION_BEFORE);
                if (!
$this->Collides($bufferItem$index))
                {
                    
$this->IndexItem($bufferItem);
                }
            }

            
$this->IndexItem($item);

            if (
$item->HasBufferTime())
            {
                
$bufferItem = new BufferItem($itemBufferItem::LOCATION_AFTER);
                if (!
$this->Collides($bufferItem$index))
                {
                    
$this->IndexItem($bufferItem);
                }
            }
        }

        
$sw->Stop();
//        Log::Debug('IndexItems() took %s seconds', $sw->GetTotalSeconds());
    
}

    private function 
IndexItem(ReservationListItem $item)
    {
        if ((
$item->StartDate()->Compare($this->_lastLayoutTime) >= 0) ||
                (
$item->EndDate()->Compare($this->_firstLayoutTime) <= 0))
        {
            
// skip the item if it starts after this layout or ends before it
            
return;
        }

        
$start $item->StartDate()->ToTimezone($this->_destinationTimezone);

        
$startsInPast $this->ItemStartsOnPastDate($item);
        if (
$startsInPast)
        {
            
$start $this->_firstLayoutTime;
        }
        elseif (
$this->ItemIsNotOnLayoutBoundary($item))
        {
            
$layoutItem $this->FindClosestLayoutIndexBeforeStartingTime($item);
            if (!empty(
$layoutItem))
            {
                
$start $layoutItem->BeginDate()->ToTimezone($this->_destinationTimezone);
            }
        }

        
$this->_itemsByStartTime[$start->Timestamp()] = $item;
    }

    private function 
ItemStartsOnPastDate(ReservationListItem $item)
    {
        
//Log::Debug("PAST");
        
return $item->StartDate()->Compare($this->_layoutDateStart) <= 0;
    }

    private function 
ItemEndsOnFutureDate(ReservationListItem $item)
    {
        
//Log::Debug("%s %s %s", $reservation->GetReferenceNumber(), $reservation->GetEndDate()->GetDate(), $this->_layoutDateEnd->GetDate());
        
return $item->EndDate()->Compare($this->_layoutDateEnd) >= 0;
    }

    private function 
IndexLayout()
    {
        
$sw StopWatch::StartNew();

        if (!
LayoutIndexCache::Contains($this->_layoutDateStart))
        {
            
LayoutIndexCache::Add($this->_layoutDateStart$this->_layoutItems$this->_layoutDateStart,
                                  
$this->_layoutDateEnd);
        }
        
$cachedIndex LayoutIndexCache::Get($this->_layoutDateStart);
        
$this->_firstLayoutTime $cachedIndex->GetFirstLayoutTime();
        
$this->_lastLayoutTime $cachedIndex->GetLastLayoutTime();
        
$this->_layoutByStartTime $cachedIndex->LayoutByStartTime();
        
$this->_layoutIndexByEndTime $cachedIndex->LayoutIndexByEndTime();

        
$sw->Stop();
//        Log::Debug('IndexLayout() took %s seconds', $sw->GetTotalSeconds());
    
}

    
/**
     * @param Date $endingTime
     * @return int index of $_layoutItems which has the corresponding $endingTime
     */
    
private function GetLayoutIndexEndingAt(Date $endingTime)
    {
        
$timeKey $endingTime->Timestamp();

        if (
array_key_exists($timeKey$this->_layoutIndexByEndTime))
        {
            return 
$this->_layoutIndexByEndTime[$timeKey];
        }

        return 
$this->FindClosestLayoutIndexBeforeEndingTime($endingTime);
    }

    
/**
     * @param Date $beginTime
     * @return ReservationListItem
     */
    
private function GetItemStartingAt(Date $beginTime)
    {
        
$timeKey $beginTime->Timestamp();
        if (
array_key_exists($timeKey$this->_itemsByStartTime))
        {
            return 
$this->_itemsByStartTime[$timeKey];
        }
        return 
null;
    }

    
/**
     * @param Date $endingTime
     * @return int index of $_layoutItems which has the closest ending time to $endingTime without going past it
     */
    
private function FindClosestLayoutIndexBeforeEndingTime(Date $endingTime)
    {
        for (
$i count($this->_layoutItems) - 1$i >= 0$i--)
        {
            
$currentItem $this->_layoutItems[$i];

            if (
$currentItem->BeginDate()->LessThan($endingTime))
            {
                return 
$i;
            }
        }

        return 
0;
    }

    
/**
     * @param ReservationListItem $item
     * @return SchedulePeriod which has the closest starting time to $endingTime without going prior to it
     */
    
private function FindClosestLayoutIndexBeforeStartingTime(ReservationListItem $item)
    {
        for (
$i count($this->_layoutItems) - 1$i >= 0$i--)
        {
            
$currentItem $this->_layoutItems[$i];

            if (
$currentItem->BeginDate()->LessThan($item->StartDate()))
            {
                return 
$currentItem;
            }
        }

        
Log::Error('Could not find a fitting starting slot for reservation. Id %s, ResourceId: %s, Start: %s, End: %s',
                   
$item->Id(), $item->ResourceId(), $item->StartDate()->ToString(), $item->EndDate()->ToString());
        return 
null;
    }

    
/**
     * @param ReservationListItem $item
     * @return bool
     */
    
private function ItemIsNotOnLayoutBoundary(ReservationListItem $item)
    {
        
$timeKey $item->StartDate()->Timestamp();
        return !(
array_key_exists($timeKey$this->_layoutByStartTime));
    }

    private function 
Collides(ReservationListItem $item$itemIndex)
    {
        
$previousItem $itemIndex $this->_items[--$itemIndex] : null;
        
$nextItem $itemIndex count($this->_items)-$this->_items[++$itemIndex] : null;

        
$itemDateRange = new DateRange($item->StartDate(), $item->EndDate());
        if (
$previousItem != null)
        {
            if (
$itemDateRange->Overlaps(new DateRange($previousItem->StartDate(), $previousItem->EndDate())))
            {
                return 
true;
            }
        }

        if (
$nextItem != null)
        {
            if (
$itemDateRange->Overlaps(new DateRange($nextItem->StartDate(), $nextItem->EndDate())))
            {
                return 
true;
            }
        }

        return 
false;
    }
}

class 
LayoutIndexCache
{
    
/**
     * @var CachedLayoutIndex[]
     */
    
private static $_cache = array();

    
/**
     * @param Date $date
     * @return bool
     */
    
public static function Contains(Date $date)
    {
        return 
array_key_exists($date->Timestamp(), self::$_cache);
    }

    
/**
     * @param Date $date
     * @param SchedulePeriod[] $schedulePeriods
     * @param Date $startDate
     * @param Date $endDate
     */
    
public static function Add(Date $date$schedulePeriodsDate $startDateDate $endDate)
    {
        
self::$_cache[$date->Timestamp()] = new CachedLayoutIndex($schedulePeriods$startDate$endDate);
    }

    public static function 
Get(Date $date)
    {
        return 
self::$_cache[$date->Timestamp()];
    }

    public static function 
Clear() { self::$_cache = array(); }
}

class 
CachedLayoutIndex
{
    private 
$_firstLayoutTime;
    private 
$_lastLayoutTime;
    private 
$_layoutByStartTime = array();
    private 
$_layoutIndexByEndTime = array();

    
/**
     * @param SchedulePeriod[] $schedulePeriods
     * @param Date $startDate
     * @param Date $endDate
     */
    
public function __construct($schedulePeriodsDate $startDateDate $endDate)
    {
        
$this->_firstLayoutTime $endDate;
        
$this->_lastLayoutTime $startDate;

        for (
$i 0$i count($schedulePeriods); $i++)
        {
            
/** @var Date $itemBegin */
            
$itemBegin $schedulePeriods[$i]->BeginDate();
            
$itemEnd $schedulePeriods[$i]->EndDate();
            if (
$itemBegin->LessThan($this->_firstLayoutTime))
            {
                
$this->_firstLayoutTime $itemBegin;
            }
            if (
$itemEnd->GreaterThan($this->_lastLayoutTime))
            {
                
$this->_lastLayoutTime $itemEnd;
            }

            
/** @var Date $endTime */
            
$endTime $schedulePeriods[$i]->EndDate();
            if (!
$schedulePeriods[$i]->EndDate()->DateEquals($startDate))
            {
                
$endTime $endDate;
            }

            
$this->_layoutByStartTime[$itemBegin->Timestamp()] = $schedulePeriods[$i];
            
$this->_layoutIndexByEndTime[$endTime->Timestamp()] = $i;
        }
    }

    public function 
GetFirstLayoutTime() { return $this->_firstLayoutTime; }

    public function 
GetLastLayoutTime() { return $this->_lastLayoutTime; }

    public function 
LayoutByStartTime() { return $this->_layoutByStartTime; }

    public function 
LayoutIndexByEndTime() { return $this->_layoutIndexByEndTime; }
}

All system for education purposes only. For more tools: Telegram @jackleet

Mr.X Private Shell

Logo
-
New File | New Folder
Command
SQL