CoolCMS API

BookingWizard extends BaseComponent
in package
uses InitTrait, SignalTrait, ModalTrait, FormTrait

FinalYes

Booking wizard: the successor of {@see \App\UI\Front\Company\Components\BookingCalendarComponent\BookingCalendar} on the new "book a time slot" page.

IMPORTANT: the old component and its page stay unchanged; this one lives next to it and shares only the SCSS file _booking_calendar.scss (extended additively).

Two states, not two steps below each other: month (day grid) and day (list of the day's slots) are persistent parameters and the day replaces the month: after a click on a day the grid is hidden and a back arrow appears on top.

The visitor chooses a calendar (the purpose, e.g. "Shop" / "Service"), not a service or worker. The switcher in the header is rendered only when there is more than one public calendar. Presentation names and descriptions come from CalendarText (fallback to the operational calendars.name) and are filtered to public = 1; the Api does both (CalendarManager::findPublicPresentation()).

Data is read fail-soft through TimeSlotManager::availability() (an Api error gives an empty month, not a crash). Writing happens in the booking modal through ReservationManager::book(); the component fetches the manager only together with the form, to hold no unused dependency.

IMPORTANT: public availability never carries the identity of foreign reservations, so the component renders only starts, never busy/confirmed/pending blocks.

Table of Contents

Constants

ERROR_MESSAGE_KEYS  : array<string|int, mixed> = [ 2 => 'form.messages.errors.validationFailed',...
`ResultCode->value` (Api) mapped to the translated message key; an unknown code gives the generic message.
MODAL_TARGET  : string = 'companyBookingWizardModal'
The only target of the wizard modal; the calendar and the form share the same window.
MONTH_KEYS  : array<string|int, mixed> = ['01' => 'jan', '02' => 'feb', '03' => 'mar', '...
`MM` mapped to a short key under `calendar.months.*` (shared with the old component, see `front.*.neon`).
WEEKDAY_KEYS  : array<string|int, mixed> = [1 => 'mon', 2 => 'tue', 3 => 'wed', 4 => 'thu'...
ISO day number (`N`) mapped to a short key under `calendar.weekdays*.*`.

Properties

$calendarId  : int
Chosen public calendar; `0` means the first public calendar of the company (see `resolveCalendarId()`).
$container  : Container
$day  : string|null
Chosen day `YYYY-MM-DD`; `null` means the "month" state (grid).
$inModal  : bool
Render mode: `false` = inline (the wizard is directly in the page), `true` = modal (the wizard lives in a modal window). Persistent so links inside the modal carry it; `render()` takes no arguments.
$month  : string
Displayed month `YYYY-MM`; empty means the server's current month (see `resolveMonth()`).
$routerDispatcher  : RouterDispatcher
$slotFrom  : string|null
Start `HH:MM` of the tapped slot; `null` means no slot chosen. Persistent because the booking form in the modal is submitted by another request and must know which block it came from (the server verifies the pair against `dayStarts` anyway; the client is not trusted).
$slotTo  : string|null
End `HH:MM` of the tapped slot; prefills `timeTo` (the `maxTo` cap is handled by `FormTrait`).
$translator  : ITranslator
$appContext  : AppContext
$componentParameters  : array<string, mixed>
$currencyContext  : CurrencyContext|null
$deviceDetector  : DeviceDetector|null
$languageContext  : LanguageContext|null
$localizationContext  : LocalizationContext|null
$settingContext  : SettingContext
$themeContext  : ThemeContext|null
$translatorDomain  : string|null
$availabilityCache  : array<string, array<string, mixed>>
Memoizes {@see TimeSlotManager::availability()} within one request, keyed by `month|calendar`; the component asks at most twice per request (the default calendar for the list of public calendars plus the chosen calendar).
$bookingMessage  : string|null
Message printed inside the modal (not through the session flash, which would duplicate the inline output on the page).
$bookingMessageType  : string
$dayStarts  : array<int, array{from: string, to: string, maxTo: string}>
Offered starts of the chosen day after the server-side lead-time trim. Computed by `InitTrait::prepareWizard()` and read by the slot-choice signal too, to verify the `(from, to)` pair sent by the client against server data, not against the template.
$eventDispatcher  : EventDispatcher
$modalRegistry  : ModalRegistry
$reservationManager  : ReservationManager
$slotLengthMinutes  : int
Slot length of the chosen calendar in minutes; the step of the end offer in the booking form.
$timeSlotManager  : TimeSlotManager

Methods

__call()  : mixed
Dispatches `renderXyz()` to `render('Xyz', ...$args)`.
__construct()  : mixed
createComponent()  : IComponent|null
getAppContext()  : AppContext
getComponentParameter()  : mixed
Returns a component parameter, or null when it is not set.
getContainer()  : Container
getCurrencyContext()  : CurrencyContext|null
getLanguageContext()  : LanguageContext|null
getLocalizationContext()  : LocalizationContext|null
getRouterDispatcher()  : RouterDispatcher
getSettingContext()  : SettingContext
getSettings()  : array<int, array<string, mixed>>
getThemeContext()  : ThemeContext|null
handleBackToCalendar()  : void
Back arrow from the booking form to the calendar (modal mode only).
handleBackToMonth()  : void
handleChangeMonth()  : void
handleSelectCalendar()  : void
handleSelectDay()  : void
handleSelectSlot()  : void
Handles a click on a slot block: opens the booking modal with the recap and the form.
handleShowCalendarModal()  : void
Handles the "book a time slot" button on the "my time slots" page: opens the wizard (month grid) in a modal window. From now on the component is in modal mode and all its links carry it in the persistent `inModal`.
hasServiceByType()  : bool
Returns whether the container has a service of the given type.
initializeAllContexts()  : void
injectDeviceDetector()  : void
onBookingFormError()  : void
Validation errors (missing consent, empty name...); the modal stays open with the form.
onBookingFormSuccess()  : void
onCreate()  : void
render()  : void
IMPORTANT: takes no arguments. The context (mode, calendar) belongs in persistent parameters and signals, otherwise an AJAX redraw of the snippet would render nothing.
renderButton()  : void
Second render mode: on the "my time slots" page the component renders only the "book a time slot" button; the whole wizard opens in a modal ({@see ModalTrait::handleShowCalendarModal()}).
setAppContext()  : $this
setComponentParameter()  : void
Sets a component parameter.
setCurrencyContext()  : $this
setLanguageContext()  : $this
setLocalizationContext()  : $this
setSettingContext()  : $this
setThemeContext()  : $this
setup()  : void
setupAppContext()  : void
typedComponent()  : T
Returns a subcomponent with a verified type.
createComponentBookingForm()  : Form
frontPresenter()  : BasePresenter|null
Returns the front presenter the component is attached to (null outside the front end or when detached).
getTranslator()  : ITranslator
setTemplateFile()  : void
setTranslator()  : self
bookableStarts()  : array<int, array{from: string, to: string, maxTo: string}>
Returns the offered day starts after the lead-time trim. The Api already trims them (free time is cut from the left by `now + leadTimeHours`), but the front end does not rely on it: time can pass between computing and rendering (cache, long request) and offering a slot the lead time no longer allows would mean a click into an error.
buildEndOptions()  : array<string, string>
Returns the ends: the union of reachable ends over all starts of the day, in steps of `slotLengthMinutes`, capped by `maxTo`. Not authoritative; the server verifies the pair again.
buildStartOptions()  : array<string, string>
Returns the starts: the server-trimmed `starts` of the chosen day ({@see InitTrait::bookableStarts()}).
buildWeeks()  : array<int, array<int, array{date: string, dayNumber: int, weekdayKey: string, state: string, freeMinutesLabel: string|null, isPast: bool, isToday: bool, bookable: bool, startCount: int}|null>>
Builds the month grid by weeks (Monday first); a `null` cell is padding outside the month and is never clickable.
createFormContent()  : string
Second view: recap + booking form.
createModalEvent()  : ModalWindowEvent
createMultiplierComponent()  : Multiplier<string|int, IComponent>
Creates a multiplier for the component.
createNewComponentInstance()  : IComponent|null
Creates a new component instance without adding it to the presenter; used by the multiplier.
createResultContent()  : string
Second view after submit: the result message instead of the form (the form is no longer offered).
createStandardComponent()  : IComponent|null
Creates a standard component (not a multiplier).
createWizardContent()  : string
First view: the same wizard (header + month/day) as in inline mode, rendered into a string.
currentMonth()  : string
fetchAvailability()  : array<string, mixed>
Returns {@see \App\UI\Front\Company\Models\Managers\TimeSlotManager::availability()} memoized for the lifetime of this component instance (one request), keyed by month and calendar.
findCalendar()  : array{id: int, name: string, description: string|null}|null
finishBooking()  : void
Success (also the silent honeypot one); the message stays in the modal and the calendar below is redrawn.
formatDayHeading()  : string
Formats `YYYY-MM-DD` as e.g. "Thursday, September 10, 2026" by the `day.heading` pattern of the language.
formatMinutes()  : string
Minutes since midnight to `H:MM` (same as the Api `TimeSlotManager::formatMinutes()`, without a cross-module import).
formatTime()  : string
Minutes since midnight to `HH:MM` (the end offer must match `starts` in shape, i.e. with a leading zero).
isDayBookable()  : bool
Applies the day clickability rules: past days are not bookable, `closed` or without starts are not, today only when at least one start remains after the `leadTimeHours` trim. Padding is handled by the template (a `null` cell) and never gets here.
openOrUpdateModal()  : void
Opens the modal or, when it already exists in the registry, only replaces its content.
prefillIdentity()  : void
prepareFormTemplate()  : void
Recap data and messages for `Sections/Form.latte`.
prepareWizard()  : void
refreshWizardAfterBooking()  : void
Second snippet next to the modal: in inline mode the redrawn calendar on the booking page, in modal mode the client's reservation list on the "my time slots" page (a new one was added).
refreshWizardView()  : void
Redraws the wizard after a navigation signal: in inline mode through the `wizard` snippet, in modal mode by replacing the modal content.
renderPartial()  : string
Renders a partial into a string (like `WatchdogFormComponent\Traits\ModalTrait`).
resolveCalendarId()  : int
Resolves the calendar id. IMPORTANT: the persistent `calendarId` from the URL is not trusted; only values from the list of public calendars of the presented company are valid. A foreign, non-public or nonsensical id falls back to the first public calendar (and `0` when the company has none).
resolveDay()  : string|null
Accepts the chosen day only when it belongs to the displayed month, exists in the Api response and is bookable; otherwise the wizard returns to the "month" state. Without this check a hand-edited URL could open the slot list of a past or closed day.
resolveErrorMessageKey()  : string
An unknown or missing code gives the generic message.
resolveMonth()  : string
`YYYY-MM`; empty, invalid or past input falls back to the server's current month.
shiftMonth()  : string
str()  : string
`ArrayHash` values are `mixed`; safely narrows to string (a non-string becomes empty).
toMinutes()  : int

Constants

ERROR_MESSAGE_KEYS

`ResultCode->value` (Api) mapped to the translated message key; an unknown code gives the generic message.

private array<string|int, mixed> ERROR_MESSAGE_KEYS = [ 2 => 'form.messages.errors.validationFailed', // occupied, in the past or lead time 4 => 'form.messages.errors.notAvailable', 303 => 'form.messages.errors.dbDuplicateEntry', 304 => 'form.messages.errors.dbLocked', 404 => 'form.messages.errors.rateLimitExceeded', ]

MODAL_TARGET

The only target of the wizard modal; the calendar and the form share the same window.

private string MODAL_TARGET = 'companyBookingWizardModal'

MONTH_KEYS

`MM` mapped to a short key under `calendar.months.*` (shared with the old component, see `front.*.neon`).

private array<string|int, mixed> MONTH_KEYS = ['01' => 'jan', '02' => 'feb', '03' => 'mar', '04' => 'apr', '05' => 'may', '06' => 'jun', '07' => 'jul', '08' => 'aug', '09' => 'sep', '10' => 'oct', '11' => 'nov', '12' => 'dec']

WEEKDAY_KEYS

ISO day number (`N`) mapped to a short key under `calendar.weekdays*.*`.

private array<string|int, mixed> WEEKDAY_KEYS = [1 => 'mon', 2 => 'tue', 3 => 'wed', 4 => 'thu', 5 => 'fri', 6 => 'sat', 7 => 'sun']

Properties

$calendarId

Chosen public calendar; `0` means the first public calendar of the company (see `resolveCalendarId()`).

public int $calendarId = 0
Attributes
#[Persistent]

$day

Chosen day `YYYY-MM-DD`; `null` means the "month" state (grid).

public string|null $day = null
Attributes
#[Persistent]

$inModal

Render mode: `false` = inline (the wizard is directly in the page), `true` = modal (the wizard lives in a modal window). Persistent so links inside the modal carry it; `render()` takes no arguments.

public bool $inModal = false
Attributes
#[Persistent]

$month

Displayed month `YYYY-MM`; empty means the server's current month (see `resolveMonth()`).

public string $month = ''
Attributes
#[Persistent]

$slotFrom

Start `HH:MM` of the tapped slot; `null` means no slot chosen. Persistent because the booking form in the modal is submitted by another request and must know which block it came from (the server verifies the pair against `dayStarts` anyway; the client is not trusted).

public string|null $slotFrom = null
Attributes
#[Persistent]

$slotTo

End `HH:MM` of the tapped slot; prefills `timeTo` (the `maxTo` cap is handled by `FormTrait`).

public string|null $slotTo = null
Attributes
#[Persistent]

$componentParameters

protected array<string, mixed> $componentParameters = []

component parameters set by setComponentParameter()

$translatorDomain

protected string|null $translatorDomain = 'front.company.components.bookingWizard'

$availabilityCache

Memoizes {@see TimeSlotManager::availability()} within one request, keyed by `month|calendar`; the component asks at most twice per request (the default calendar for the list of public calendars plus the chosen calendar).

private array<string, array<string, mixed>> $availabilityCache = []

The return type is deliberately loose: availability is fail-soft and consumers guard the keys.

$bookingMessage

Message printed inside the modal (not through the session flash, which would duplicate the inline output on the page).

private string|null $bookingMessage = null

$bookingMessageType

private string $bookingMessageType = 'alert-info'

$dayStarts

Offered starts of the chosen day after the server-side lead-time trim. Computed by `InitTrait::prepareWizard()` and read by the slot-choice signal too, to verify the `(from, to)` pair sent by the client against server data, not against the template.

private array<int, array{from: string, to: string, maxTo: string}> $dayStarts = []

$slotLengthMinutes

Slot length of the chosen calendar in minutes; the step of the end offer in the booking form.

private int $slotLengthMinutes = 0

Methods

__call()

Dispatches `renderXyz()` to `render('Xyz', ...$args)`.

public __call(string $name, array<string|int, mixed> $args) : mixed

Called only when the component has no renderXyz() method of its own.

Parameters
$name : string
$args : array<string|int, mixed>

createComponent()

public createComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

getComponentParameter()

Returns a component parameter, or null when it is not set.

public getComponentParameter(string $name) : mixed
Parameters
$name : string

getContainer()

public getContainer() : Container
Return values
Container

getSettings()

public getSettings() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>>

handleBackToCalendar()

Back arrow from the booking form to the calendar (modal mode only).

public handleBackToCalendar() : void

handleBackToMonth()

public handleBackToMonth() : void

handleChangeMonth()

public handleChangeMonth(string $month) : void
Parameters
$month : string

handleSelectCalendar()

public handleSelectCalendar(int $calendarId) : void
Parameters
$calendarId : int

handleSelectDay()

public handleSelectDay(string $day) : void
Parameters
$day : string

handleSelectSlot()

Handles a click on a slot block: opens the booking modal with the recap and the form.

public handleSelectSlot(string $from, string $to) : void

IMPORTANT: the (from, to) pair is verified against the server-computed starts of the chosen day; the client is not trusted even here. An invalid pair does not open the modal, it only says the slot is gone.

Parameters
$from : string
$to : string

handleShowCalendarModal()

Handles the "book a time slot" button on the "my time slots" page: opens the wizard (month grid) in a modal window. From now on the component is in modal mode and all its links carry it in the persistent `inModal`.

public handleShowCalendarModal() : void

hasServiceByType()

Returns whether the container has a service of the given type.

public hasServiceByType(string $className) : bool

The name is composed dynamically (module plus component), so class_exists() runs first, and a true result guarantees a valid type.

Parameters
$className : string
Tags
phpstan-assert-if-true

class-string $className

Return values
bool

onBookingFormError()

Validation errors (missing consent, empty name...); the modal stays open with the form.

public onBookingFormError(Form $form) : void
Parameters
$form : Form

onBookingFormSuccess()

public onBookingFormSuccess(Form $form, ArrayHash $values) : void
Parameters
$form : Form
$values : ArrayHash

render()

IMPORTANT: takes no arguments. The context (mode, calendar) belongs in persistent parameters and signals, otherwise an AJAX redraw of the snippet would render nothing.

public render() : void

renderButton()

Second render mode: on the "my time slots" page the component renders only the "book a time slot" button; the whole wizard opens in a modal ({@see ModalTrait::handleShowCalendarModal()}).

public renderButton() : void

The grid is deliberately not built here (no prepareWizard()); one availability query is enough to tell whether the company has reservations enabled and a public calendar. Without it the button would lead to an empty modal.

setComponentParameter()

Sets a component parameter.

public setComponentParameter(string $name, mixed $value) : void
Parameters
$name : string
$value : mixed

typedComponent()

Returns a subcomponent with a verified type.

public typedComponent(string $name, T> $type) : T

Use it instead of an inline @var above $this['x'] (which does not narrow the type) and instead of the generic IComponent that $this['x'] returns. See Form::typedComponent().

Parameters
$name : string
$type : T>
Tags
template
Return values
T

createComponentBookingForm()

protected createComponentBookingForm() : Form
Return values
Form

frontPresenter()

Returns the front presenter the component is attached to (null outside the front end or when detached).

protected frontPresenter() : BasePresenter|null
Return values
BasePresenter|null

getTranslator()

protected getTranslator() : ITranslator
Return values
ITranslator

setTemplateFile()

protected setTemplateFile(string $dir, string $filename) : void
Parameters
$dir : string
$filename : string

setTranslator()

protected setTranslator(ITranslator $translator) : self
Parameters
$translator : ITranslator
Return values
self

bookableStarts()

Returns the offered day starts after the lead-time trim. The Api already trims them (free time is cut from the left by `now + leadTimeHours`), but the front end does not rely on it: time can pass between computing and rendering (cache, long request) and offering a slot the lead time no longer allows would mean a click into an error.

private static bookableStarts(string $date, mixed $dayData, int $leadTimeHours) : array<int, array{from: string, to: string, maxTo: string}>
Parameters
$date : string
$dayData : mixed

raw day payload from the fail-soft Api response (can be anything)

$leadTimeHours : int
Return values
array<int, array{from: string, to: string, maxTo: string}>

buildEndOptions()

Returns the ends: the union of reachable ends over all starts of the day, in steps of `slotLengthMinutes`, capped by `maxTo`. Not authoritative; the server verifies the pair again.

private buildEndOptions() : array<string, string>
Return values
array<string, string>

buildStartOptions()

Returns the starts: the server-trimmed `starts` of the chosen day ({@see InitTrait::bookableStarts()}).

private buildStartOptions() : array<string, string>
Return values
array<string, string>

buildWeeks()

Builds the month grid by weeks (Monday first); a `null` cell is padding outside the month and is never clickable.

private static buildWeeks(string $month, array<string, mixed> $days, int $leadTimeHours) : array<int, array<int, array{date: string, dayNumber: int, weekdayKey: string, state: string, freeMinutesLabel: string|null, isPast: bool, isToday: bool, bookable: bool, startCount: int}|null>>
Parameters
$month : string
$days : array<string, mixed>
$leadTimeHours : int

trim of today; computed here, not in Latte

Return values
array<int, array<int, array{date: string, dayNumber: int, weekdayKey: string, state: string, freeMinutesLabel: string|null, isPast: bool, isToday: bool, bookable: bool, startCount: int}|null>>

createFormContent()

Second view: recap + booking form.

private createFormContent() : string
Return values
string

createModalEvent()

private createModalEvent(string $content[, array<string, mixed> $extraOptions = [] ]) : ModalWindowEvent
Parameters
$content : string
$extraOptions : array<string, mixed> = []
Return values
ModalWindowEvent

createMultiplierComponent()

Creates a multiplier for the component.

private createMultiplierComponent(string $name) : Multiplier<string|int, IComponent>
Parameters
$name : string
Return values
Multiplier<string|int, IComponent>

createNewComponentInstance()

Creates a new component instance without adding it to the presenter; used by the multiplier.

private createNewComponentInstance(string $baseName[, int|string|null $uniqueKey = null ]) : IComponent|null
Parameters
$baseName : string
$uniqueKey : int|string|null = null
Return values
IComponent|null

createResultContent()

Second view after submit: the result message instead of the form (the form is no longer offered).

private createResultContent() : string
Return values
string

createStandardComponent()

Creates a standard component (not a multiplier).

private createStandardComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

createWizardContent()

First view: the same wizard (header + month/day) as in inline mode, rendered into a string.

private createWizardContent() : string
Return values
string

currentMonth()

private static currentMonth() : string
Return values
string

fetchAvailability()

Returns {@see \App\UI\Front\Company\Models\Managers\TimeSlotManager::availability()} memoized for the lifetime of this component instance (one request), keyed by month and calendar.

private fetchAvailability(string $month, int $calendarId) : array<string, mixed>
Parameters
$month : string
$calendarId : int
Return values
array<string, mixed>

findCalendar()

private findCalendar(array<int, array{id: int, name: string, description: string|null}> $calendars, int $calendarId) : array{id: int, name: string, description: string|null}|null
Parameters
$calendars : array<int, array{id: int, name: string, description: string|null}>
$calendarId : int
Return values
array{id: int, name: string, description: string|null}|null

finishBooking()

Success (also the silent honeypot one); the message stays in the modal and the calendar below is redrawn.

private finishBooking(string $messageKey, string $type) : void
Parameters
$messageKey : string
$type : string

formatDayHeading()

Formats `YYYY-MM-DD` as e.g. "Thursday, September 10, 2026" by the `day.heading` pattern of the language.

private formatDayHeading(string $day) : string

IMPORTANT: built in PHP because both variable parts are translations (calendar.weekdaysLong.*, calendar.monthsInflected.*) and the order differs per language; in Latte this would need a nested {_} inside a {_} parameter.

Parameters
$day : string
Return values
string

formatMinutes()

Minutes since midnight to `H:MM` (same as the Api `TimeSlotManager::formatMinutes()`, without a cross-module import).

private static formatMinutes(int $minutes) : string
Parameters
$minutes : int
Return values
string

formatTime()

Minutes since midnight to `HH:MM` (the end offer must match `starts` in shape, i.e. with a leading zero).

private static formatTime(int $minutes) : string
Parameters
$minutes : int
Return values
string

isDayBookable()

Applies the day clickability rules: past days are not bookable, `closed` or without starts are not, today only when at least one start remains after the `leadTimeHours` trim. Padding is handled by the template (a `null` cell) and never gets here.

private static isDayBookable(string $date, mixed $dayData, int $leadTimeHours) : bool
Parameters
$date : string
$dayData : mixed

raw day payload from the fail-soft Api response (can be anything)

$leadTimeHours : int
Return values
bool

openOrUpdateModal()

Opens the modal or, when it already exists in the registry, only replaces its content.

private openOrUpdateModal(string $content) : void

IMPORTANT: the distinction is required. ADDED redraws the whole modal container, which would drop the Bootstrap instance of an already open window; UPDATE touches only the modalBody snippet, so the window stays open and only its inside changes (flash inside the modal plus a redrawn calendar).

Parameters
$content : string

prefillIdentity()

private static prefillIdentity(Form $form, User|null $user) : void
Parameters
$form : Form
$user : User|null

prepareFormTemplate()

Recap data and messages for `Sections/Form.latte`.

private prepareFormTemplate() : void

prepareWizard()

private prepareWizard() : void

refreshWizardAfterBooking()

Second snippet next to the modal: in inline mode the redrawn calendar on the booking page, in modal mode the client's reservation list on the "my time slots" page (a new one was added).

private refreshWizardAfterBooking() : void

refreshWizardView()

Redraws the wizard after a navigation signal: in inline mode through the `wizard` snippet, in modal mode by replacing the modal content.

private refreshWizardView() : void

renderPartial()

Renders a partial into a string (like `WatchdogFormComponent\Traits\ModalTrait`).

private renderPartial(string $file, string $errorMessageKey) : string

A template failure must not crash the request; the modal shows a message instead of the content.

Parameters
$file : string
$errorMessageKey : string
Return values
string

resolveCalendarId()

Resolves the calendar id. IMPORTANT: the persistent `calendarId` from the URL is not trusted; only values from the list of public calendars of the presented company are valid. A foreign, non-public or nonsensical id falls back to the first public calendar (and `0` when the company has none).

private resolveCalendarId(array<int, array{id: int, name: string, description: string|null}> $calendars) : int
Parameters
$calendars : array<int, array{id: int, name: string, description: string|null}>
Return values
int

resolveDay()

Accepts the chosen day only when it belongs to the displayed month, exists in the Api response and is bookable; otherwise the wizard returns to the "month" state. Without this check a hand-edited URL could open the slot list of a past or closed day.

private resolveDay(array<string, mixed> $days, int $leadTimeHours) : string|null
Parameters
$days : array<string, mixed>
$leadTimeHours : int
Return values
string|null

resolveErrorMessageKey()

An unknown or missing code gives the generic message.

private static resolveErrorMessageKey(mixed $code) : string
Parameters
$code : mixed
Return values
string

resolveMonth()

`YYYY-MM`; empty, invalid or past input falls back to the server's current month.

private static resolveMonth(string|null $month) : string
Parameters
$month : string|null
Return values
string

shiftMonth()

private static shiftMonth(string $month, int $delta) : string
Parameters
$month : string
$delta : int
Return values
string

str()

`ArrayHash` values are `mixed`; safely narrows to string (a non-string becomes empty).

private static str(mixed $value) : string
Parameters
$value : mixed
Return values
string

toMinutes()

private static toMinutes(string $time) : int
Parameters
$time : string
Return values
int
On this page

Search results