MyWorkDetail
extends BaseComponent
in package
uses
InitTrait, SignalTrait, FormTrait
Detail of one job of the client: the job header, the table of work items and the expansion of one work item (persistent `$work`): description, hours/rate/price and the comment thread with a form for adding a message.
A job outside the ownership (foreign or nonexistent) gives one uniform "job not found" empty
state; setWorkListId() only passes the id and the ownership is verified on the server:
the job header is looked up in the client's own myList result and the work items come from
myItems (WorkItemManager::findForOwnedList()).
Same approach as BookingCalendarComponent (persistent parameter + signal + memoized fetch
available before render(), see InitTrait).
Table of Contents
Constants
- ERROR_MESSAGE_KEYS : array<string|int, mixed> = [2 => 'comments.form.messages.errors.validation...
- `code` of the Api response (`mixed` because of `ReflectionException`) mapped to the translated message key.
Properties
- $container : Container
- $routerDispatcher : RouterDispatcher
- $translator : ITranslator
- $work : int|null
- Expanded work item; `null` means only the job table without a work item detail.
- $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
-
$itemsCache
: WorkSheet>, unreadComments: array
} |null - Memoizes {@see WorkItemManager::findMyItems()} within one request, for the same reason as `$listsCache`: the guard "the chosen work item belongs to this job" of `prepareWorkDetail()` (see `InitTrait::fetchItems()`) needs the same data as the grouping by work sheet in `prepareDetail()`, and a signal/form success calls `prepareWorkDetail()` separately, possibly before `prepareDetail()`.
-
$listsCache
: WorkList>, totalCount: int, workItemCounts: array
} |null - Memoizes {@see WorkListManager::findMyLists()} within one request; the comment form can be created before `render()` (a signal/form POST calls `createComponent*()` first), see `InitTrait::fetchLists()`.
- $workItemManager : WorkItemManager
- $workListId : int
- Id of the displayed job; set by the presenter ({@see setWorkListId()}) after `actionDetail()`.
- $workListManager : WorkListManager
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
- handleSelectWork() : void
- hasServiceByType() : bool
- Returns whether the container has a service of the given type.
- initializeAllContexts() : void
- injectDeviceDetector() : void
- onCommentFormSuccess() : void
- onCreate() : void
- render() : void
- setAppContext() : $this
- setComponentParameter() : void
- Sets a component parameter.
- setCurrencyContext() : $this
- setLanguageContext() : $this
- setLocalizationContext() : $this
- setSettingContext() : $this
- setThemeContext() : $this
- setup() : void
- setupAppContext() : void
- setWorkListId() : self
- typedComponent() : T
- Returns a subcomponent with a verified type.
- createComponentCommentForm() : 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
- belongsToCurrentList() : bool
- Tells whether the expanded work item belongs to the job `$this->workListId` (replaces the removed `WorkItem::getWorkListId()`, see {@see prepareWorkDetail()}). `myItems` returns only the work items of this job (the server verified ownership), so membership in the {@see fetchItems()} result is the answer.
- 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.
- createStandardComponent() : IComponent|null
- Creates a standard component (not a multiplier).
-
fetchItems()
: WorkSheet>, unreadComments: array
} - Returns `WorkItemManager::findMyItems()` memoized for the lifetime of this component instance, for the same reason as {@see fetchLists()}: the guard of `prepareWorkDetail()` ({@see belongsToCurrentList()}) can run before `render()` and `prepareDetail()` calls it again; without memoization that would be two bridge queries per request.
-
fetchLists()
: WorkList>, totalCount: int, workItemCounts: array
} - Returns `WorkListManager::findMyLists()` memoized for the lifetime of this component instance (one request). Required because the comment form can be created before `render()` (a form POST calls `createComponent*()` first); same as {@see \App\UI\Front\Company\Components\BookingCalendarComponent\Traits\InitTrait::fetchAvailability()}.
- findOwnedList() : WorkList|null
- Returns the owned job from `myList` by `$this->workListId`, or `null` (foreign or nonexistent).
- groupItemsBySheet() : array<int, WorkItem>, sumHours: string, sumPrice: string}>
- Groups work items by work sheet for the template (sheet heading + its items + hours/price sum per group).
- prepareDetail() : void
- prepareEmptyWorkDetail() : void
- prepareWorkDetail() : void
- resolveMessageKey() : string
- An unknown or missing code gives the generic message.
- str() : string
- `ArrayHash` values are `mixed`; safely narrows to string (a non-string becomes empty).
- sumGroupHours() : string
- Returns the hours sum of a group: the same value as shown on the row (`actualHours ?? estimatedHours`, {@see \App\UI\Front\Company\Components\MyWorkDetailComponent\Templates\Default\Sections\Items.latte}), so the sum matches the table above it.
- sumGroupPrice() : string
Constants
ERROR_MESSAGE_KEYS
`code` of the Api response (`mixed` because of `ReflectionException`) mapped to the translated message key.
private
array<string|int, mixed>
ERROR_MESSAGE_KEYS
= [2 => 'comments.form.messages.errors.validationFailed', 404 => 'comments.form.messages.errors.rateLimitExceeded']
Properties
$container
public
Container
$container
Attributes
- #[Inject]
$routerDispatcher
public
RouterDispatcher
$routerDispatcher
$translator
public
ITranslator
$translator
Tags
$work
Expanded work item; `null` means only the job table without a work item detail.
public
int|null
$work
= null
Attributes
- #[Persistent]
$appContext
protected
AppContext
$appContext
$componentParameters
protected
array<string, mixed>
$componentParameters
= []
component parameters set by setComponentParameter()
$currencyContext
protected
CurrencyContext|null
$currencyContext
= NULL
$deviceDetector
protected
DeviceDetector|null
$deviceDetector
= NULL
$languageContext
protected
LanguageContext|null
$languageContext
= NULL
$localizationContext
protected
LocalizationContext|null
$localizationContext
= NULL
$settingContext
protected
SettingContext
$settingContext
$themeContext
protected
ThemeContext|null
$themeContext
= NULL
$translatorDomain
protected
string|null
$translatorDomain
= 'front.company.components.myWorkDetail'
$itemsCache
Memoizes {@see WorkItemManager::findMyItems()} within one request, for the same reason as `$listsCache`: the guard "the chosen work item belongs to this job" of `prepareWorkDetail()` (see `InitTrait::fetchItems()`) needs the same data as the grouping by work sheet in `prepareDetail()`, and a signal/form success calls `prepareWorkDetail()` separately, possibly before `prepareDetail()`.
private
WorkSheet>, unreadComments: array} |null
$itemsCache
= null
$listsCache
Memoizes {@see WorkListManager::findMyLists()} within one request; the comment form can be created before `render()` (a signal/form POST calls `createComponent*()` first), see `InitTrait::fetchLists()`.
private
WorkList>, totalCount: int, workItemCounts: array} |null
$listsCache
= null
$workItemManager read-only
private
WorkItemManager
$workItemManager
$workListId
Id of the displayed job; set by the presenter ({@see setWorkListId()}) after `actionDetail()`.
private
int
$workListId
= 0
$workListManager read-only
private
WorkListManager
$workListManager
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>
__construct()
public
__construct(WorkListManager $workListManager, WorkItemManager $workItemManager) : mixed
Parameters
- $workListManager : WorkListManager
- $workItemManager : WorkItemManager
createComponent()
public
createComponent(string $name) : IComponent|null
Parameters
- $name : string
Return values
IComponent|nullgetAppContext()
public
getAppContext() : AppContext
Return values
AppContextgetComponentParameter()
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
ContainergetCurrencyContext()
public
getCurrencyContext() : CurrencyContext|null
Return values
CurrencyContext|nullgetLanguageContext()
public
getLanguageContext() : LanguageContext|null
Return values
LanguageContext|nullgetLocalizationContext()
public
getLocalizationContext() : LocalizationContext|null
Return values
LocalizationContext|nullgetRouterDispatcher()
public
getRouterDispatcher() : RouterDispatcher
Return values
RouterDispatchergetSettingContext()
public
getSettingContext() : SettingContext
Return values
SettingContextgetSettings()
public
getSettings() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>>getThemeContext()
public
getThemeContext() : ThemeContext|null
Return values
ThemeContext|nullhandleSelectWork()
public
handleSelectWork(int $workId) : void
Parameters
- $workId : int
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
Return values
boolinitializeAllContexts()
public
initializeAllContexts() : void
injectDeviceDetector()
public
injectDeviceDetector(DeviceDetector $detector) : void
Parameters
- $detector : DeviceDetector
onCommentFormSuccess()
public
onCommentFormSuccess(Form $form, ArrayHash $values) : void
Parameters
- $form : Form
- $values : ArrayHash
onCreate()
public
onCreate() : void
render()
public
render([string $style = 'Detail' ]) : void
Parameters
- $style : string = 'Detail'
setAppContext()
public
setAppContext(AppContext $appContext) : $this
Parameters
- $appContext : AppContext
Return values
$thissetComponentParameter()
Sets a component parameter.
public
setComponentParameter(string $name, mixed $value) : void
Parameters
- $name : string
- $value : mixed
setCurrencyContext()
public
setCurrencyContext(CurrencyContext|null $currencyContext) : $this
Parameters
- $currencyContext : CurrencyContext|null
Return values
$thissetLanguageContext()
public
setLanguageContext(LanguageContext|null $languageContext) : $this
Parameters
- $languageContext : LanguageContext|null
Return values
$thissetLocalizationContext()
public
setLocalizationContext(LocalizationContext|null $localizationContext) : $this
Parameters
- $localizationContext : LocalizationContext|null
Return values
$thissetSettingContext()
public
setSettingContext(SettingContext $settingContext) : $this
Parameters
- $settingContext : SettingContext
Return values
$thissetThemeContext()
public
setThemeContext(ThemeContext|null $themeContext) : $this
Parameters
- $themeContext : ThemeContext|null
Return values
$thissetup()
public
setup(BasePresenter|BasePresenter $presenter) : void
Parameters
- $presenter : BasePresenter|BasePresenter
setupAppContext()
public
setupAppContext(AppContext $appContext) : void
Parameters
- $appContext : AppContext
setWorkListId()
public
setWorkListId(int $workListId) : self
Parameters
- $workListId : int
Return values
selftypedComponent()
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
Return values
TcreateComponentCommentForm()
protected
createComponentCommentForm() : Form
Return values
FormfrontPresenter()
Returns the front presenter the component is attached to (null outside the front end or when detached).
protected
frontPresenter() : BasePresenter|null
Return values
BasePresenter|nullgetTranslator()
protected
getTranslator() : ITranslator
Return values
ITranslatorsetTemplateFile()
protected
setTemplateFile(string $dir, string $filename) : void
Parameters
- $dir : string
- $filename : string
setTranslator()
protected
setTranslator(ITranslator $translator) : self
Parameters
- $translator : ITranslator
Return values
selfbelongsToCurrentList()
Tells whether the expanded work item belongs to the job `$this->workListId` (replaces the removed `WorkItem::getWorkListId()`, see {@see prepareWorkDetail()}). `myItems` returns only the work items of this job (the server verified ownership), so membership in the {@see fetchItems()} result is the answer.
private
belongsToCurrentList(WorkItem $detail) : bool
Parameters
- $detail : WorkItem
Return values
boolcreateMultiplierComponent()
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|nullcreateStandardComponent()
Creates a standard component (not a multiplier).
private
createStandardComponent(string $name) : IComponent|null
Parameters
- $name : string
Return values
IComponent|nullfetchItems()
Returns `WorkItemManager::findMyItems()` memoized for the lifetime of this component instance, for the same reason as {@see fetchLists()}: the guard of `prepareWorkDetail()` ({@see belongsToCurrentList()}) can run before `render()` and `prepareDetail()` calls it again; without memoization that would be two bridge queries per request.
private
fetchItems() : WorkSheet>, unreadComments: array}
Return values
WorkSheet>, unreadComments: arrayfetchLists()
Returns `WorkListManager::findMyLists()` memoized for the lifetime of this component instance (one request). Required because the comment form can be created before `render()` (a form POST calls `createComponent*()` first); same as {@see \App\UI\Front\Company\Components\BookingCalendarComponent\Traits\InitTrait::fetchAvailability()}.
private
fetchLists() : WorkList>, totalCount: int, workItemCounts: array}
Return values
WorkList>, totalCount: int, workItemCounts: arrayfindOwnedList()
Returns the owned job from `myList` by `$this->workListId`, or `null` (foreign or nonexistent).
private
findOwnedList() : WorkList|null
Return values
WorkList|nullgroupItemsBySheet()
Groups work items by work sheet for the template (sheet heading + its items + hours/price sum per group).
private
groupItemsBySheet(array<int, WorkItem> $items, array<int, WorkSheet> $sheets) : array<int, WorkItem>, sumHours: string, sumPrice: string}>
IMPORTANT: the group order follows the first occurrence in $items. The Api returns them
already sorted work_sheets.order -> work_items.order -> id
(WorkItemManager::sortForInvoice()), i.e. exactly in
the order they would go on the invoice. They are not sorted again here, only grouped, so the
order never differs from what the client sees on the document.
An item without _references (should not happen, every work item has a sheet) gets
sheet: null; the template then shows the work item without a sheet header rather than silently
dropping it (degrade, not fatal, as in EntityHydrator).
Sums are computed by the server (PHP), not in the template; bcadd is used because of the
decimal columns (decimal in the DB, string on the entity), like
WorkListManager::sumItemPrices().
Parameters
Return values
array<int, WorkItem>, sumHours: string, sumPrice: string}>prepareDetail()
private
prepareDetail() : void
prepareEmptyWorkDetail()
private
prepareEmptyWorkDetail() : void
prepareWorkDetail()
private
prepareWorkDetail() : void
resolveMessageKey()
An unknown or missing code gives the generic message.
private
static resolveMessageKey(bool $success, bool $approved, mixed $code) : string
Parameters
- $success : bool
- $approved : bool
- $code : mixed
Return values
stringstr()
`ArrayHash` values are `mixed`; safely narrows to string (a non-string becomes empty).
private
static str(mixed $value) : string
Parameters
- $value : mixed
Return values
stringsumGroupHours()
Returns the hours sum of a group: the same value as shown on the row (`actualHours ?? estimatedHours`, {@see \App\UI\Front\Company\Components\MyWorkDetailComponent\Templates\Default\Sections\Items.latte}), so the sum matches the table above it.
private
sumGroupHours(array<int, WorkItem> $items) : string
Parameters
- $items : array<int, WorkItem>
Return values
stringsumGroupPrice()
private
sumGroupPrice(array<int, WorkItem> $items) : string
Parameters
- $items : array<int, WorkItem>