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/Domain/      ( Reset | Go to )
File Name: ScheduleLayout.php
Edit
<?php
/**
Copyright 2011-2014 Nick Korbel

This file is part of Booked Scheduler.

Booked Scheduler 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 version.

Booked Scheduler 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
along with Booked Scheduler.  If not, see <http://www.gnu.org/licenses/>.
 */

require_once(ROOT_DIR 'Domain/Values/DayOfWeek.php');

interface 
ILayoutTimezone
{
    public function 
Timezone();
}

interface 
IDailyScheduleLayout
{
    
/**
     * @return bool
     */
    
public function UsesDailyLayouts();
}

interface 
IScheduleLayout extends ILayoutTimezoneIDailyScheduleLayout
{
    
/**
     * @param Date $layoutDate
     * @param bool $hideBlockedPeriods
     * @return SchedulePeriod[]|array of SchedulePeriod objects
     */
    
public function GetLayout(Date $layoutDate$hideBlockedPeriods false);

    
/**
     * @abstract
     * @param Date $date
     * @return SchedulePeriod|null period which occurs at this datetime. Includes start time, excludes end time. null if no match is found
     */
    
public function GetPeriod(Date $date);
}

interface 
ILayoutCreation extends ILayoutTimezoneIDailyScheduleLayout
{
    
/**
     * Appends a period to the schedule layout
     *
     * @param Time $startTime starting time of the schedule in specified timezone
     * @param Time $endTime ending time of the schedule in specified timezone
     * @param string $label optional label for the period
     * @param DayOfWeek|int|null $dayOfWeek
     */
    
function AppendPeriod(Time $startTimeTime $endTime$label null$dayOfWeek null);

    
/**
     * Appends a period that is not reservable to the schedule layout
     *
     * @param Time $startTime starting time of the schedule in specified timezone
     * @param Time $endTime ending time of the schedule in specified timezone
     * @param string $label optional label for the period
     * @param DayOfWeek|int|null $dayOfWeek
     * @return void
     */
    
function AppendBlockedPeriod(Time $startTimeTime $endTime$label null$dayOfWeek null);

    
/**
     *
     * @param DayOfWeek|int|null $dayOfWeek
     * @return LayoutPeriod[] array of LayoutPeriod
     */
    
function GetSlots($dayOfWeek null);
}

class 
ScheduleLayout implements IScheduleLayoutILayoutCreation
{
    
/**
     * @var array|LayoutPeriod[]
     */
    
private $_periods = array();

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

    
/**
     * @var bool
     */
    
private $cached false;

    private 
$cachedPeriods = array();

    
/**
     * @var bool
     */
    
private $usingDailyLayouts false;

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

    
/**
     * @param string $targetTimezone target timezone of layout
     */
    
public function __construct($targetTimezone null)
    {
        
$this->targetTimezone $targetTimezone;
        if (
$targetTimezone == null)
        {
            
$this->targetTimezone Configuration::Instance()->GetDefaultTimezone();
        }
    }

    
/**
     * @param DayOfWeek|int|null $dayOfWeek
     * @throws Exception
     * @return LayoutPeriod[]|array
     */
    
public function GetSlots($dayOfWeek null)
    {
        if (
is_null($dayOfWeek))
        {
            if (
$this->usingDailyLayouts)
            {
                throw new 
Exception('ScheduleLayout->GetSlots() $dayOfWeek required when using daily layouts');
            }
            
$periods $this->_periods;
        }
        else
        {
            if (!
$this->usingDailyLayouts)
            {
                throw new 
Exception('ScheduleLayout->GetSlots() $dayOfWeek cannot be provided when using single layout');
            }
            
$periods $this->_periods[$dayOfWeek];
        }
        
$this->SortItems($periods);
        return 
$periods;
    }

    
/**
     * Appends a period to the schedule layout
     *
     * @param Time $startTime starting time of the schedule in specified timezone
     * @param Time $endTime ending time of the schedule in specified timezone
     * @param string $label optional label for the period
     * @param DayOfWeek|int|null $dayOfWeek
     */
    
public function AppendPeriod(Time $startTimeTime $endTime$label null$dayOfWeek null)
    {
        
$this->AppendGenericPeriod($startTime$endTimePeriodTypes::RESERVABLE$label$dayOfWeek);
    }

    
/**
     * Appends a period that is not reservable to the schedule layout
     *
     * @param Time $startTime starting time of the schedule in specified timezone
     * @param Time $endTime ending time of the schedule in specified timezone
     * @param string $label optional label for the period
     * @param DayOfWeek|int|null $dayOfWeek
     * @return void
     */
    
public function AppendBlockedPeriod(Time $startTimeTime $endTime$label null$dayOfWeek null)
    {
        
$this->AppendGenericPeriod($startTime$endTimePeriodTypes::NONRESERVABLE$label$dayOfWeek);
    }

    protected function 
AppendGenericPeriod(Time $startTimeTime $endTime$periodType$label null,
                                           
$dayOfWeek null)
    {
        
$this->layoutTimezone $startTime->Timezone();
        
$layoutPeriod = new LayoutPeriod($startTime$endTime$periodType$label);
        if (!
is_null($dayOfWeek))
        {
            
$this->usingDailyLayouts true;
            
$this->_periods[$dayOfWeek][] = $layoutPeriod;
        }
        else
        {
            
$this->_periods[] = $layoutPeriod;
        }
    }

    
/**
     * @param Date $start
     * @param Date $end
     * @return bool
     */
    
protected function SpansMidnight(Date $startDate $end)
    {
        return !
$start->DateEquals($end) && !$end->IsMidnight();
    }

    
/**
     * @param Date $layoutDate
     * @param bool $hideBlockedPeriods
     * @return array|SchedulePeriod[]
     */
    
public function GetLayout(Date $layoutDate$hideBlockedPeriods false)
    {
        if (
$this->usingDailyLayouts)
        {
            return 
$this->GetLayoutDaily($layoutDate$hideBlockedPeriods);
        }
        
$targetTimezone $this->targetTimezone;
        
$layoutDate $layoutDate->ToTimezone($targetTimezone);

        
$cachedValues $this->GetCachedValuesForDate($layoutDate);
        if (!empty(
$cachedValues))
        {
            return 
$cachedValues;
        }

        
$list = new PeriodList();

        
$periods $this->getPeriods($layoutDate);

        if (
count($periods) <= 0)
        {
            throw new 
Exception(sprintf('No periods defined for date %s'$layoutDate));
        }

        
$layoutTimezone $periods[0]->Timezone();
        
$workingDate Date::Create($layoutDate->Year(), $layoutDate->Month(), $layoutDate->Day(), 000,
                                    
$layoutTimezone);
        
$midnight $layoutDate->GetDate();

        
/* @var $period LayoutPeriod */
        
foreach ($periods as $period)
        {
            if (
$hideBlockedPeriods && !$period->IsReservable())
            {
                continue;
            }
            
$start $period->Start;
            
$end $period->End;
            
$periodType $period->PeriodTypeClass();
            
$label $period->Label;
            
$labelEnd null;

            
// convert to target timezone
            
$periodStart $workingDate->SetTime($start)->ToTimezone($targetTimezone);
            
$periodEnd $workingDate->SetTime($endtrue)->ToTimezone($targetTimezone);

            if (
$periodEnd->LessThan($periodStart))
            {
                
$periodEnd $periodEnd->AddDays(1);
            }

            
$startTime $periodStart->GetTime();
            
$endTime $periodEnd->GetTime();

            if (
$this->BothDatesAreOff($periodStart$periodEnd$layoutDate))
            {
                
$periodStart $layoutDate->SetTime($startTime);
                
$periodEnd $layoutDate->SetTime($endTimetrue);
            }

            if (
$this->SpansMidnight($periodStart$periodEnd$layoutDate))
            {
                if (
$periodStart->LessThan($midnight))
                {
                    
// add compensating period at end
                    
$start $layoutDate->SetTime($startTime);
                    
$end $periodEnd->AddDays(1);
                    
$list->Add($this->BuildPeriod($periodType$start$end$label$labelEnd));
                }
                else
                {
                    
// add compensating period at start
                    
$start $periodStart->AddDays(-1);
                    
$end $layoutDate->SetTime($endTimetrue);
                    
$list->Add($this->BuildPeriod($periodType$start$end$label$labelEnd));
                }
            }

            if (!
$periodStart->IsMidnight() && $periodStart->LessThan($layoutDate) && $periodEnd->DateEquals($layoutDate) && $periodEnd->IsMidnight())
            {
                
$periodStart $periodStart->AddDays(1);
                
$periodEnd $periodEnd->AddDays(1);
            }

            
$list->Add($this->BuildPeriod($periodType$periodStart$periodEnd$label$labelEnd));
        }

        
$layout $list->GetItems();
        
$this->SortItems($layout);
        
$this->AddCached($layout$workingDate);

        return 
$layout;
    }

    private function 
GetLayoutDaily(Date $requestedDate$hideBlockedPeriods false)
    {
        if (
$requestedDate->Timezone() != $this->targetTimezone)
        {
            throw new 
Exception('Target timezone and requested timezone do not match');
        }

        
$cachedValues $this->GetCachedValuesForDate($requestedDate);
        if (!empty(
$cachedValues))
        {
            return 
$cachedValues;
        }

        
// check cache
        
$baseDateInLayoutTz Date::Create($requestedDate->Year(), $requestedDate->Month(), $requestedDate->Day(),
                                           
000$this->layoutTimezone);


        
$list = new PeriodList();
        
$this->AddDailyPeriods($requestedDate->Weekday(), $baseDateInLayoutTz$requestedDate$list$hideBlockedPeriods);

        if (
$this->layoutTimezone != $this->targetTimezone)
        {
            
$requestedDateInTargetTz $requestedDate->ToTimezone($this->layoutTimezone);

            
$adjustment 0;
            if (
$requestedDateInTargetTz->Format('YmdH') < $requestedDate->Format('YmdH'))
            {
                
$adjustment = -1;
            }
            else
            {
                if (
$requestedDateInTargetTz->Format('YmdH') > $requestedDate->Format('YmdH'))
                {
                    
$adjustment 1;
                }
            }

            if (
$adjustment != 0)
            {
                
$adjustedDate $requestedDate->AddDays($adjustment);
                
$baseDateInLayoutTz $baseDateInLayoutTz->AddDays($adjustment);
                
$this->AddDailyPeriods($adjustedDate->Weekday(), $baseDateInLayoutTz$requestedDate$list);
            }
        }
        
$layout $list->GetItems();
        
$this->SortItems($layout);
        
$this->AddCached($layout$requestedDate);
        return 
$layout;
    }

    
/**
     * @param int $day
     * @param Date $baseDateInLayoutTz
     * @param Date $requestedDate
     * @param PeriodList $list
     * @param bool $hideBlockedPeriods
     */
    
private function AddDailyPeriods($day$baseDateInLayoutTz$requestedDate$list$hideBlockedPeriods false)
    {
        
$periods $this->_periods[$day];
        
/** @var $period LayoutPeriod */
        
foreach ($periods as $period)
        {
            if (
$hideBlockedPeriods && !$period->IsReservable())
            {
                continue;
            }
            
$begin $baseDateInLayoutTz->SetTime($period->Start)->ToTimezone($this->targetTimezone);
            
$end $baseDateInLayoutTz->SetTime($period->Endtrue)->ToTimezone($this->targetTimezone);
            
// only add this period if it occurs on the requested date
            
if ($begin->DateEquals($requestedDate) || ($end->DateEquals($requestedDate) && !$end->IsMidnight()))
            {
                
$built $this->BuildPeriod($period->PeriodTypeClass(), $begin$end$period->Label);
                
$list->Add($built);
            }
        }
    }

    
/**
     * @param array|SchedulePeriod[] $layout
     * @param Date $date
     */
    
private function AddCached($layout$date)
    {
        
$this->cached true;
        
$this->cachedPeriods[$date->Format('Ymd')] = $layout;
    }

    
/**
     * @param Date $date
     * @return array|SchedulePeriod[]
     */
    
private function GetCachedValuesForDate($date)
    {
        
$key $date->Format('Ymd');
        if (
array_key_exists($date->Format('Ymd'), $this->cachedPeriods))
        {
            return 
$this->cachedPeriods[$key];
        }
        return 
null;
    }

    private function 
BothDatesAreOff(Date $startDate $endDate $layoutDate)
    {
        return !
$start->DateEquals($layoutDate) && !$end->DateEquals($layoutDate);
    }

    private function 
BuildPeriod($periodTypeDate $startDate $end$label$labelEnd null)
    {
        return new 
$periodType($start$end$label$labelEnd);
    }

    protected function 
SortItems(&$items)
    {
        
usort($items, array("ScheduleLayout""SortBeginTimes"));
    }

    public function 
Timezone()
    {
        return 
$this->targetTimezone;
    }

    protected function 
AddPeriod(SchedulePeriod $period)
    {
        
$this->_periods[] = $period;
    }

    
/**
     * @static
     * @param SchedulePeriod|LayoutPeriod $period1
     * @param SchedulePeriod|LayoutPeriod $period2
     * @return int
     */
    
static function SortBeginTimes($period1$period2)
    {
        return 
$period1->Compare($period2);
    }

    
/**
     * @param string $timezone
     * @param string $reservableSlots
     * @param string $blockedSlots
     * @return ScheduleLayout
     */
    
public static function Parse($timezone$reservableSlots$blockedSlots)
    {
        
$parser = new LayoutParser($timezone);
        
$parser->AddReservable($reservableSlots);
        
$parser->AddBlocked($blockedSlots);
        return 
$parser->GetLayout();
    }

    
/**
     * @param string $timezone
     * @param string[]|array $reservableSlots
     * @param string[]|array $blockedSlots
     * @throws Exception
     * @return ScheduleLayout
     */
    
public static function ParseDaily($timezone$reservableSlots$blockedSlots)
    {
        if (
count($reservableSlots) != DayOfWeek::NumberOfDays || count($blockedSlots) != DayOfWeek::NumberOfDays)
        {
            throw new 
Exception(sprintf('LayoutParser ParseDaily missing slots. $reservableSlots=%s, $blockedSlots=%s',
                                        
count($reservableSlots), count($blockedSlots)));
        }
        
$parser = new LayoutParser($timezone);

        foreach (
DayOfWeek::Days() as $day)
        {
            
$parser->AddReservable($reservableSlots[$day], $day);
            
$parser->AddBlocked($blockedSlots[$day], $day);
        }

        return 
$parser->GetLayout();
    }

    
/**
     * @param Date $date
     * @return SchedulePeriod period which occurs at this datetime. Includes start time, excludes end time
     */
    
public function GetPeriod(Date $date)
    {
        
$timezone $this->layoutTimezone;
        
$tempDate $date->ToTimezone($timezone);
        
$periods $this->getPeriods($tempDate);

        
/** @var $period LayoutPeriod */
        
foreach ($periods as $period)
        {
            
$start Date::Create($tempDate->Year(), $tempDate->Month(), $tempDate->Day(), $period->Start->Hour(),
                                  
$period->Start->Minute(), 0$timezone);
            
$end Date::Create($tempDate->Year(), $tempDate->Month(), $tempDate->Day(), $period->End->Hour(),
                                
$period->End->Minute(), 0$timezone);

            if (
$end->LessThan($start) || $end->IsMidnight())
            {
                
$end $end->AddDays(1);
            }

            if (
$start->Compare($date) <= && $end->Compare($date) > 0)
            {
                return 
$this->BuildPeriod($period->PeriodTypeClass(), $start$end$period->Label);
            }
        }

        return 
null;
    }

    
/**
     * @return bool
     */
    
public function UsesDailyLayouts()
    {
        return 
$this->usingDailyLayouts;
    }

    private function 
getPeriods(Date $layoutDate)
    {
        if (
$this->usingDailyLayouts)
        {
            
$dayOfWeek $layoutDate->Weekday();
            return 
$this->_periods[$dayOfWeek];
        }
        else
        {
            return 
$this->_periods;
        }
    }
}

class 
LayoutParser
{
    private 
$layout;
    private 
$timezone;

    public function 
__construct($timezone)
    {
        
$this->layout = new ScheduleLayout($timezone);
        
$this->timezone $timezone;
    }

    public function 
AddReservable($reservableSlots$dayOfWeek null)
    {
        
$cb = array($this'appendPeriod');
        
$this->ParseSlots($reservableSlots$dayOfWeek$cb);
    }

    public function 
AddBlocked($blockedSlots$dayOfWeek null)
    {
        
$cb = array($this'appendBlocked');

        
$this->ParseSlots($blockedSlots$dayOfWeek$cb);
    }

    public function 
GetLayout()
    {
        return 
$this->layout;
    }

    private function 
appendPeriod($start$end$label$dayOfWeek null)
    {
        
$this->layout->AppendPeriod(Time::Parse($start$this->timezone),
                                    
Time::Parse($end$this->timezone),
                                    
$label,
                                    
$dayOfWeek);
    }

    private function 
appendBlocked($start$end$label$dayOfWeek null)
    {
        
$this->layout->AppendBlockedPeriod(Time::Parse($start$this->timezone),
                                           
Time::Parse($end$this->timezone),
                                           
$label,
                                           
$dayOfWeek);
    }

    private function 
ParseSlots($allSlots$dayOfWeek$callback)
    {
        
$lines preg_split("/[\n]/"$allSlots, -1PREG_SPLIT_NO_EMPTY);

        foreach (
$lines as $slotLine)
        {
            
$label null;
            
$parts preg_split('/(\d?\d:\d\d\s*\-\s*\d?\d:\d\d)(.*)/'trim($slotLine), -1,
                                
PREG_SPLIT_NO_EMPTY PREG_SPLIT_DELIM_CAPTURE);
            
$times explode('-'$parts[0]);
            
$start trim($times[0]);
            
$end trim($times[1]);

            if (
count($parts) > 1)
            {
                
$label trim($parts[1]);
            }

            
call_user_func($callback$start$end$label$dayOfWeek);
        }
    }
}

class 
LayoutPeriod
{
    
/**
     * @var Time
     */
    
public $Start;

    
/**
     * @var Time
     */
    
public $End;

    
/**
     * @var PeriodTypes
     */
    
public $PeriodType;

    
/**
     * @var string
     */
    
public $Label;

    
/**
     * @return string
     */
    
public function PeriodTypeClass()
    {
        if (
$this->PeriodType == PeriodTypes::RESERVABLE)
        {
            return 
'SchedulePeriod';
        }

        return 
'NonSchedulePeriod';
    }

    
/**
     * @return bool
     */
    
public function IsReservable()
    {
        return 
$this->PeriodType == PeriodTypes::RESERVABLE;
    }

    
/**
     * @return bool
     */
    
public function IsLabelled()
    {
        return !empty(
$this->Label);
    }

    
/**
     * @return string
     */
    
public function Timezone()
    {
        return 
$this->Start->Timezone();
    }

    public function 
__construct(Time $startTime $end$periodType PeriodTypes::RESERVABLE$label null)
    {
        
$this->Start $start;
        
$this->End $end;
        
$this->PeriodType $periodType;
        
$this->Label $label;
    }

    
/**
     * Compares the starting times
     */
    
public function Compare(LayoutPeriod $other)
    {
        return 
$this->Start->Compare($other->Start);
    }
}

class 
PeriodList
{
    private 
$items = array();
    private 
$_addedStarts = array();
    private 
$_addedTimes = array();
    private 
$_addedEnds = array();

    public function 
Add(SchedulePeriod $period)
    {
        if (
$this->AlreadyAdded($period->BeginDate(), $period->EndDate()))
        {
            return;
        }

        
$this->items[] = $period;
    }

    public function 
GetItems()
    {
        return 
$this->items;
    }

    private function 
AlreadyAdded(Date $startDate $end)
    {
        
$startExists false;
        
$endExists false;

        if (
array_key_exists($start->Timestamp(), $this->_addedStarts))
        {
            
$startExists true;
        }

        if (
array_key_exists($end->Timestamp(), $this->_addedEnds))
        {
            
$endExists true;
        }

        
$this->_addedTimes[$start->Timestamp()] = true;
        
$this->_addedEnds[$end->Timestamp()] = true;

        return 
$startExists || $endExists;
    }
}

class 
ReservationLayout extends ScheduleLayout implements IScheduleLayout
{
    protected function 
SpansMidnight(Date $startDate $end)
    {
        return 
false;
    }
}

?>

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

Mr.X Private Shell

Logo
-
New File | New Folder
Command
SQL