KMP PHP API Reference

RecommendationsController extends AppController
in package
uses DataverseGridTrait, WorkflowDispatchTrait

Recommendations Controller

Manages the complete award recommendation lifecycle from submission through final disposition. Implements state machine-based workflow with table views. Supports authenticated and public submission workflows.

Uses DataverseGridTrait for table-based data display.

Table of Contents

Constants

MOBILE_QUEUE_DEFAULT_PER_PAGE  : int = 25
MOBILE_QUEUE_MAX_PER_PAGE  : int = 50
VIEW_DATA_EVENT  : string = 'KMP.plugins.callForViewData'
VIEW_PLUGIN_EVENT  : string = 'KMP.plugins.callForViewCells'
BESTOWAL_GATHERING_REQUIRED_KEY  : mixed = 'requires_bestowal_gathering'
BESTOWAL_GATHERING_WORKFLOW_SLUGS  : mixed = ['awards-recommendation-submitted', 'awards-exi...

Properties

$Recommendations  : RecommendationsTable
$isCsvRequest  : bool
$pluginViewCells  : array<string|int, mixed>
$pluginViewCellsEnabledForFragment  : bool
Whether an intentionally fragment-style response still needs plugin view cells.

Methods

add()  : Response|null|void
Display the recommendation submission form for authenticated users and process posted submissions.
beforeFilter()  : Response|null|void
Configure authentication for public recommendation submission helpers.
beforeRender()  : Response|null|void
Finalize view-only data after the action has run.
bulkWorkflowDecision()  : Response|null
Record one decision against multiple selected recommendation workflow approvals.
delete()  : Response|null
Delete a recommendation with transaction safety.
edit()  : Response|null|void
Edit an existing recommendation with member data synchronization.
gatheringsAutoComplete()  : void
Return gathering autocomplete options for recommendation edit/quick-edit forms.
gatheringsForAward()  : void
Return gatherings linked to an award, optionally including attendance indicators for a member.
getFilteredGatheringsForAward()  : array<string|int, mixed>
Retrieve gatherings linked to an award and format them for display, optionally marking member attendance.
gridData()  : Response|null|void
Grid Data method - provides data for the Dataverse grid
groupChildren()  : void
AJAX endpoint: return grouped children HTML for a recommendation sub-row.
groupRecommendations()  : Response|null
Group selected recommendations together.
index()  : Response|null|void
Recommendation system landing page.
initialize()  : void
Initialize Awards Plugin Base Controller.
isCsvRequest()  : bool
Check if current request is for CSV export.
memberSubmittedRecsGridData()  : Response|null|void
Grid Data for "Submitted By Member" context
recsForMemberGridData()  : Response|null|void
Grid Data for "Recs For Member" context
removeFromGroup()  : Response|null
Remove a single child from its group.
requestFeedback()  : Response|null
Request feedback on selected recommendations or recommendation groups.
retractFeedback()  : Response|null
Retract a pending recommendation feedback request.
startApprovalWorkflow()  : Response|null
Start a fresh approval workflow from a recommendation screen.
submitRecommendation()  : Response|null
Render and process the public recommendation submission form for guest users.
switchView()  : Response
Switch between mobile and desktop view modes.
turboEditForm()  : Response|null
Render a populated edit form for a recommendation intended for Turbo Frame partial updates.
ungroupRecommendations()  : Response|null
Ungroup all children from a group head.
view()  : Response|null
Display a single recommendation with its workflow context and related entities.
workflowDecision()  : Response|null
Record the current user's approval decision from a recommendation screen.
workflowDecisionFromGrid()  : Response|null
Record a grid approval decision for the current user's pending recommendation approval.
applyCustomFilterHandlers()  : SelectQuery
Apply custom filter handlers for columns with complex filtering logic
applyHiddenStateVisibility()  : SelectQuery
Apply hidden-state visibility constraints to a recommendations query.
applyStateFilterOptionsToGridResult()  : array<string|int, mixed>
Inject dynamic state filter options into a Dataverse grid result payload.
appSettingImageDataUri()  : string|null
Resolve shared tenant branding for the online and cached mobile templates.
assertSafeContextUrl()  : string
Ensure URL is same-origin relative path + query only.
authorizeCurrentUrl()  : void
Authorize the current URL/action via Authorization component.
buildDataverseGridSearchCondition()  : array<string, mixed>|null
Build a search condition for one Dataverse grid column.
buildDataverseGridState()  : array<string|int, mixed>
Build complete grid state object (single source of truth)
buildExportDataFromEntities()  : array<string|int, mixed>
Build export data from pre-processed entities (Data Mode)
buildExportDataFromQuery()  : array<string|int, mixed>
Build export data from database query (Query Mode)
buildGatheringsExportValue()  : string
Build gatherings export text showing combined recommendation events and member attendance.
buildGatheringsHtml()  : string
Build gatherings HTML showing combined recommendation events and member attendance.
buildGridDataUrlFromPageContext()  : string
Build grid-data URL preserving query string from page context.
buildNotesHtml()  : string
Build notes HTML for recommendation with popover showing all notes
buildOpLinksHtml()  : string
Build OP (Order of Precedence) links HTML for a recommendation
buildReasonHtml()  : string
Build reason HTML with popover for full text if it exceeds 50 characters
consumeFlashForStream()  : array<string, mixed>
Read flash from session and clear it for stream rendering.
convertDateBoundaryToUtc()  : string
Convert a date boundary string from kingdom timezone to UTC for SQL comparison.
dispatchWorkflowEvent()  : void
Fire a workflow event without fallback. Silently logs on failure.
dispatchWorkflowOrFail()  : array<int, mixed>
Dispatch to the workflow engine and fail when no active definition is available.
enablePluginViewCellsForFragment()  : void
Include route-matched plugin cells in an AJAX or other fragment response.
extractContextValue()  : mixed
Extract a matching value from the workflow context or its nested payload arrays.
extractExportValue()  : string
Extract export value from entity using column metadata
extractFilterFromExpression()  : mixed
Recursively extract a filter value from an expression tree
extractFilterFromSystemView()  : mixed
Extract a specific filter value from a system view configuration
extractFilterFromViewConfig()  : mixed
Extract a specific filter value from a saved user view's config
extractFilterGrouping()  : array<string|int, mixed>
Extract filter grouping information from expression tree
extractLockedDateRangeDefaults()  : array<string, array{value: string|null, operator: string}>
Extract canonical bounds for active date-range filters whose fields are locked.
extractNumericContextValue()  : int|null
Extract a numeric value from top-level or nested workflow context arrays.
extractStringContextValue()  : string|null
Extract a string value from top-level or nested workflow context arrays.
extractSystemViewDefaults()  : array{filters: array, dateRange: array, dateRangeOperators: array, search: ?string, skipFilterColumns: array}
Extract default filters/search metadata for a system view configuration
formatExportValue()  : string
Format value for CSV export
getMemberAttendanceGatherings()  : array<int, array<string|int, Gathering>>
Fetch gatherings where members are attending with share_with_crown or share_with_kingdom enabled.
getPageContextUrl()  : string|null
Posted page context URL (path + query), validated.
handleCsvExport()  : Response
Handle CSV export from grid result
isCsvExportRequest()  : bool
Check if the current request is for CSV export
isDataverseTableFrameRequest()  : bool
isGridOriginRequest()  : bool
Whether POST originated from a grid index (stay on list).
loadAvailableViews()  : array<int, mixed>
Load and cache available views for the current request.
loadFilterOptions()  : array<string|int, mixed>
Load filter options from a data source
loadFilterOptionsCached()  : array<int, array{value: string, label: string}>
Load filter options with per-request cache.
matchesGridIndexPath()  : bool
Whether page context path matches a grid index route pattern.
mobileQueuePagination()  : array<string, int|bool>
Build shared pagination values for mobile actionable queues.
mobileQueuePaginationPayload()  : array<string, int|bool>
Remove internal pagination values before sending the mobile JSON payload.
operationCategorySummary()  : string
Build a plain-text summary from trusted category labels and their counts.
operationReasonSummary()  : string
Build a bounded, plain-text count of operational result reasons.
organizeViewCells()  : array<string|int, mixed>
Organize view cells by type and display order.
prepareRecommendationsForExport()  : iterable<string|int, mixed>
Prepare recommendations for CSV export with computed fields
processDataverseGrid()  : array<string|int, mixed>
Process dataverse grid request with unified logic
renderDataverseGridResponse()  : void
Render consistent dataverse grid responses for outer/table turbo frames.
renderDataverseTableRowElement()  : string
Render a single Dataverse grid row element (Turbo Stream replace target HTML).
renderTurboCloseModal()  : Response
Render turbo-stream: flash + replace table frame with lazy reload src.
renderTurboFlashOnly()  : Response
Render turbo-stream flash messages without forcing a grid or frame reload.
renderTurboReloadFrame()  : Response
Stream that reloads an edit turbo-frame (validation errors).
renderTurboRemoveGridRow()  : Response
Render turbo-stream: flash + remove a grid row (no longer matches current filters).
renderTurboReplaceGridRow()  : Response
Render turbo-stream: flash + replace a single grid row by DOM id.
resolveBranchIdFromContextMember()  : int|null
Resolve a branch ID from member identifiers carried in workflow context.
resolveDataverseGridQueryContext()  : DataverseGridQueryContext
Resolve Dataverse grid column context for early query construction.
resolveKingdomId()  : int|null
Resolve the kingdom ID from the authenticated member or workflow context.
resolveKingdomIdFromBranch()  : int|null
Walk the branch parent chain to find the kingdom-type ancestor.
resolveNestedValue()  : mixed
Resolve nested value from entity using dot notation path
wantsTurboStreamRequest()  : bool
Whether the client expects a turbo-stream response.
withPageContextQuery()  : T
Run a callback with query params from the posted page context URL.
appendActiveRecommendationColumns()  : array<int, string>
applyDataverseGridSort()  : SelectQuery
Apply a standard field sort or delegate to a column-specific sort handler.
approvalRequiresBestowalGatheringSelection()  : bool
Determine whether this recommendation approval must schedule the created bestowal.
augmentApproverConfigForResponse()  : array<string, mixed>
awardApprovalFinalStepState()  : bool|null
buildBestowalGatheringLookupUrl()  : string
canViewLinkedBestowal()  : bool
Check whether the current identity can view the linked bestowal for a recommendation row.
collectDataverseExpressionColumnKeys()  : void
columnKeyForDataverseField()  : string
decoratePendingWorkflowApprovals()  : void
Add current-user pending approval metadata for recommendation grid actions.
defaultRecommendationVisibleColumns()  : array<int, string>
dispatchRecommendationFollowUpWorkflow()  : void
Dispatch a post-commit workflow event returned by the recommendation mutation.
dispatchRecommendationMutation()  : Recommendation}
Dispatch a workflow-backed recommendation mutation and normalize its result.
enrichRecommendationsForGrid()  : void
Add computed display fields used by the recommendations Dataverse grid.
enrichRecommendationsForGridContext()  : void
extractDataverseGridConfigColumnKeys()  : array<int, string>
extractRecommendationIdFromResult()  : int|null
Extract the saved recommendation ID from a normalized mutation result.
filterRecommendationGridActionsForResult()  : array<string, mixed>
filterRecommendationRowActionsForGridResult()  : array<string, array<string, mixed>>
findActiveDefinition()  : WorkflowDefinition|null
Find an active workflow definition by slug.
getApprovalDecisionService()  : RecommendationApprovalDecisionService
Build the approval decision service using the current workflow dispatcher.
getPendingApprovalForMember()  : WorkflowApproval|null
getPendingApprovalsForMember()  : array<int, WorkflowApproval>
getPostedBestowalGatheringId()  : int|null
getPostedRecommendationId()  : int|null
getRecommendationForApproval()  : Recommendation|null
isArchivedRecommendationResult()  : bool
Check the semantic archived filter so copied views keep archived-only actions.
isDataverseGridNumericSearchColumn()  : bool
isRecommendationColumnVisible()  : bool
Determine whether a recommendation column should be treated as visible.
isSelectableBestowalGathering()  : bool
isSelectableBestowalGatheringForRecommendation()  : bool
isWorkflowDispatchResult()  : bool
Determine whether the result is a list of workflow engine service results.
loadRecommendationGridViewColumns()  : array<int, string>|null
normalizeApproverConfig()  : array<string, mixed>
normalizeDataverseGridColumnConfig()  : array<int, string>
normalizeLockedDateBoundary()  : string|null
Normalize a persisted date boundary while retaining an intentionally open bound.
normalizeRecommendationColumns()  : array<int, string>
normalizeRecommendationMutationResult()  : Recommendation}
Normalize legacy service results and workflow-dispatch results to one controller shape.
normalizeWorkflowDispatchResult()  : Recommendation}
Collapse workflow dispatch results down to the workflow end-node result payload.
pageContextQueryTab()  : string|null
Tab query param from page context URL (detail pages).
parseIdList()  : array<string|int, int>
Parse comma or whitespace separated numeric IDs.
parseMemberIdList()  : array<string|int, int>
Parse member IDs from normal member lookup values.
recommendationsGridRefreshResponse()  : Response|null
Turbo-stream table refresh for recommendation grid actions.
recordWorkflowApprovalDecision()  : ServiceResult
requiresBestowalGatheringSelection()  : bool
resolveDataverseGridActiveColumns()  : array<int, string>
Resolve hidden-but-active query dependency columns.
resolveDataverseGridViewContext()  : array{selectedSystemView: array|null, currentView: mixed}
Resolve active saved/system view enough for pre-query column dependency planning.
resolveDataverseGridVisibleColumns()  : array<int, string>
Resolve UI-visible columns using the same precedence as processDataverseGrid().
resolveRecommendationGridRowSync()  : array{action: string, rowDomId: string, rowHtml?: string}|null
Resolve targeted row sync after a single recommendation save.
resolveRecommendationGridSyncContext()  : array{contextKey: string, tableFrameId: string, memberId?: int, gatheringId?: int}|null
Match page context to a recommendation grid row-sync context.
resolveRecommendationVisibleColumns()  : array<int, string>|null
Resolve visible columns early so recommendation queries can skip hidden display-only associations.
shouldIncludeRecommendationColumn()  : bool
Determine whether a column is requested for the current grid request.
tryRecommendationsGridTurboResponse()  : Response|null
Turbo-stream response for grid-origin recommendation saves.
validateBestowalGatheringSelection()  : string|null
validateWorkflowDecision()  : string|null

Constants

MOBILE_QUEUE_DEFAULT_PER_PAGE

public int MOBILE_QUEUE_DEFAULT_PER_PAGE = 25

Shared default page size for mobile actionable queues.

MOBILE_QUEUE_MAX_PER_PAGE

public int MOBILE_QUEUE_MAX_PER_PAGE = 50

Shared maximum page size for mobile actionable queues.

VIEW_DATA_EVENT

public string VIEW_DATA_EVENT = 'KMP.plugins.callForViewData'

Event for plugin view data enhancement

VIEW_PLUGIN_EVENT

public string VIEW_PLUGIN_EVENT = 'KMP.plugins.callForViewCells'

Event for plugin view cell registration

BESTOWAL_GATHERING_REQUIRED_KEY

private mixed BESTOWAL_GATHERING_REQUIRED_KEY = 'requires_bestowal_gathering'

BESTOWAL_GATHERING_WORKFLOW_SLUGS

private mixed BESTOWAL_GATHERING_WORKFLOW_SLUGS = ['awards-recommendation-submitted', 'awards-existing-recommendation-approval']

Properties

$isCsvRequest

protected bool $isCsvRequest = false

Whether current request is for CSV export (.csv extension)

$pluginViewCells

protected array<string|int, mixed> $pluginViewCells = []

View cells from plugins for current request

$pluginViewCellsEnabledForFragment

Whether an intentionally fragment-style response still needs plugin view cells.

protected bool $pluginViewCellsEnabledForFragment = false

Methods

add()

Display the recommendation submission form for authenticated users and process posted submissions.

public add(RecommendationSubmissionService $submissionService, TriggerDispatcher $triggerDispatcher) : Response|null|void

Creates a new Recommendation linked to the current user, optionally associates member data and preferences, initializes workflow state fields and court preference defaults, saves the record within a database transaction, and either redirects on success or re-renders the form with dropdown data (awards, domains, levels, branches, gatherings).

Parameters
$submissionService : RecommendationSubmissionService
$triggerDispatcher : TriggerDispatcher
Tags
see
submitRecommendation()

For the unauthenticated public submission workflow

view()

For recommendation detail display after submission

Recommendation

For recommendation entity structure

Return values
Response|null|void

Redirects on successful submission or renders the form on GET / validation failure

beforeFilter()

Configure authentication for public recommendation submission helpers.

public beforeFilter(EventInterface $event) : Response|null|void
Parameters
$event : EventInterface

The beforeFilter event instance

Return values
Response|null|void

beforeRender()

Finalize view-only data after the action has run.

public beforeRender(EventInterface<string|int, Controller$event) : Response|null|void

Deferring view cells prevents redirect-only requests from executing badge callbacks.

Parameters
$event : EventInterface<string|int, Controller>

Event.

Return values
Response|null|void

bulkWorkflowDecision()

Record one decision against multiple selected recommendation workflow approvals.

public bulkWorkflowDecision(TriggerDispatcher $triggerDispatcher) : Response|null
Parameters
$triggerDispatcher : TriggerDispatcher

Trigger dispatcher.

Return values
Response|null

delete()

Delete a recommendation with transaction safety.

public delete(TriggerDispatcher $triggerDispatcher[, string|null $id = null ]) : Response|null

Performs soft deletion of the recommendation after authorization validation.

Parameters
$triggerDispatcher : TriggerDispatcher
$id : string|null = null

Recommendation ID to delete

Tags
throws
NotFoundException

When recommendation not found

Return values
Response|null

Redirects to index page after deletion

edit()

Edit an existing recommendation with member data synchronization.

public edit(RecommendationUpdateService $updateService, TriggerDispatcher $triggerDispatcher, RecommendationQueryService $queryService[, string|null $id = null ]) : Response|null|void

Handles recommendation updates including member assignment changes, court preference synchronization, and optional note creation within a database transaction.

Parameters
$updateService : RecommendationUpdateService
$triggerDispatcher : TriggerDispatcher
$queryService : RecommendationQueryService
$id : string|null = null

Recommendation ID to edit

Tags
throws
NotFoundException

When recommendation not found

Return values
Response|null|void

Redirects on successful edit or to current page

gatheringsAutoComplete()

Return gathering autocomplete options for recommendation edit/quick-edit forms.

public gatheringsAutoComplete([string|null $awardId = null ]) : void

Returns Ajax HTML list items consumed by the shared auto-complete controller.

Parameters
$awardId : string|null = null

Award ID for gathering activity filtering.

gatheringsForAward()

Return gatherings linked to an award, optionally including attendance indicators for a member.

public gatheringsForAward([string|null $awardId = null ]) : void

Renders a JSON array where each item contains: id, name, display (formatted branch and date range, with an appended * when the member is attending and sharing with crown), has_attendance, and share_with_crown.

Parameters
$awardId : string|null = null

The award ID to filter gatherings for.

Tags
throws
NotFoundException

When the specified award cannot be found.

getFilteredGatheringsForAward()

Retrieve gatherings linked to an award and format them for display, optionally marking member attendance.

public getFilteredGatheringsForAward(int $awardId[, int|null $memberId = null ][, bool $futureOnly = true ][, int|null $includeGatheringId = null ][, array<string|int, int> $includeGatheringIds = [] ]) : array<string|int, mixed>
Parameters
$awardId : int

The award ID whose linked gatherings should be returned.

$memberId : int|null = null

Optional member ID; when provided, gatherings the member attends with share_with_crown enabled are marked.

$futureOnly : bool = true

When true, include only gatherings with a start date in the future.

$includeGatheringId : int|null = null

If provided, ensure this gathering ID is included in the results even if it would be excluded by the activity or date filters.

$includeGatheringIds : array<string|int, int> = []

Additional gathering IDs to include (for recommendation-selected gatherings).

Return values
array<string|int, mixed>

Associative array mapping gathering ID => formatted display string ("Name in Branch on YYYY-MM-DD - YYYY-MM-DD"); entries with an asterisk indicate the member is attending and sharing with crown.

gridData()

Grid Data method - provides data for the Dataverse grid

public gridData(CsvExportService $csvExportService, RecommendationQueryService $queryService) : Response|null|void

This method handles the AJAX requests from the dv_grid element, providing recommendation data with proper filtering, sorting, pagination, and authorization. It supports status-based system views and permission-based state filtering.

Parameters
$csvExportService : CsvExportService

Injected CSV export service

$queryService : RecommendationQueryService
Return values
Response|null|void

Renders view or returns CSV response

groupChildren()

AJAX endpoint: return grouped children HTML for a recommendation sub-row.

public groupChildren(int $headId) : void
Parameters
$headId : int

The group head recommendation ID

groupRecommendations()

Group selected recommendations together.

public groupRecommendations(RecommendationGroupingService $groupingService, TriggerDispatcher $triggerDispatcher) : Response|null

Validates that all selected recommendations share the same member_id or have null member_id. If one selected rec is already a group head, others join it. Otherwise, the lowest-ID rec becomes the head. Children transition to "Linked" state.

Parameters
$groupingService : RecommendationGroupingService
$triggerDispatcher : TriggerDispatcher
Return values
Response|null

index()

Recommendation system landing page.

public index() : Response|null|void

Primary entry point rendering the Dataverse grid interface. Grid data is loaded lazily via gridData() action.

Return values
Response|null|void

initialize()

Initialize Awards Plugin Base Controller.

public initialize() : void

Loads Authentication, Authorization, and Flash components.

isCsvRequest()

Check if current request is for CSV export.

public isCsvRequest() : bool
Return values
bool

memberSubmittedRecsGridData()

Grid Data for "Submitted By Member" context

public memberSubmittedRecsGridData(CsvExportService $csvExportService, RecommendationQueryService $queryService[, int|null $memberId = null ]) : Response|null|void

Provides recommendation data for recommendations submitted by a specific member. Used in the member profile's "Submitted Award Recs" tab.

Parameters
$csvExportService : CsvExportService

Injected CSV export service

$queryService : RecommendationQueryService
$memberId : int|null = null

The member ID whose submissions to show (-1 for current user)

Return values
Response|null|void

Renders view or returns CSV response

recsForMemberGridData()

Grid Data for "Recs For Member" context

public recsForMemberGridData(CsvExportService $csvExportService, RecommendationQueryService $queryService[, int|null $memberId = null ]) : Response|null|void

Provides recommendation data for recommendations about a specific member. Used in the member profile's "Recs For Member" tab.

Parameters
$csvExportService : CsvExportService

Injected CSV export service

$queryService : RecommendationQueryService
$memberId : int|null = null

The member ID whose received recommendations to show

Return values
Response|null|void

Renders view or returns CSV response

startApprovalWorkflow()

Start a fresh approval workflow from a recommendation screen.

public startApprovalWorkflow(TriggerDispatcher $triggerDispatcher[, string|null $id = null ]) : Response|null
Parameters
$triggerDispatcher : TriggerDispatcher

Trigger dispatcher.

$id : string|null = null

Recommendation ID.

Return values
Response|null

submitRecommendation()

Render and process the public recommendation submission form for guest users.

public submitRecommendation(RecommendationSubmissionService $submissionService, TriggerDispatcher $triggerDispatcher) : Response|null

Presents a guest-facing form to submit award recommendations and handles form submissions, creating a new recommendation record while applying necessary defaults and minimal member-data integration when a matching member is provided.

Parameters
$submissionService : RecommendationSubmissionService
$triggerDispatcher : TriggerDispatcher
Tags
see
add()

For authenticated member submission workflow

beforeFilter()

For authentication bypass configuration

Return values
Response|null

Redirects authenticated users or after successful redirects; otherwise renders the form.

switchView()

Switch between mobile and desktop view modes.

public switchView() : Response

Stores preference in session and redirects to appropriate interface. Mobile redirects to viewMobileCard, desktop to profile.

Return values
Response

Redirect response

turboEditForm()

Render a populated edit form for a recommendation intended for Turbo Frame partial updates.

public turboEditForm(RecommendationFormService $formService[, string|null $id = null ]) : Response|null

Loads the recommendation and related lookup data so the Turbo Frame can display an in-place edit form.

Parameters
$formService : RecommendationFormService
$id : string|null = null

Recommendation ID to load for the form

Tags
throws
NotFoundException

If the recommendation cannot be found

see
edit()

For form submission handling

Return values
Response|null

A Response when the action issues an explicit response, or null after setting view variables for rendering

view()

Display a single recommendation with its workflow context and related entities.

public view([string|null $id = null ]) : Response|null

Loads the recommendation together with related data (requester, member, branch, award, gatherings) and authorizes view access before exposing the entity to the view layer.

Parameters
$id : string|null = null

The recommendation ID to display.

Tags
throws
NotFoundException

If the recommendation does not exist or is inaccessible.

Return values
Response|null

The response for the rendered view, or null if the controller does not return a response.

workflowDecision()

Record the current user's approval decision from a recommendation screen.

public workflowDecision(TriggerDispatcher $triggerDispatcher[, string|null $id = null ]) : Response|null
Parameters
$triggerDispatcher : TriggerDispatcher

Trigger dispatcher.

$id : string|null = null

Recommendation ID.

Return values
Response|null

workflowDecisionFromGrid()

Record a grid approval decision for the current user's pending recommendation approval.

public workflowDecisionFromGrid(TriggerDispatcher $triggerDispatcher) : Response|null
Parameters
$triggerDispatcher : TriggerDispatcher

Trigger dispatcher.

Return values
Response|null

applyCustomFilterHandlers()

Apply custom filter handlers for columns with complex filtering logic

protected applyCustomFilterHandlers(SelectQuery $query, array<string|int, mixed> $customFilterColumns, string $tableName, array<string|int, mixed> $currentFilters, mixed $currentView, array<string|int, mixed>|null $selectedSystemView, bool $dirtyFilters) : SelectQuery

Columns can define a customFilterHandler in their metadata to specify a static method that handles their filtering. This allows complex filter logic (like querying multiple tables) to be defined alongside the column definition rather than requiring special controller knowledge.

Filter values are extracted from:

  1. Canonical current filter state (query parameters plus enforced locked values)
  2. Saved user view configuration (when loading a saved view)
  3. System view configuration (when loading a system view)
Parameters
$query : SelectQuery

The query to filter

$customFilterColumns : array<string|int, mixed>

Columns with customFilterHandler defined

$tableName : string

The main table name

$currentFilters : array<string|int, mixed>

Current filter values from query params

$currentView : mixed

Current saved user view (or null)

$selectedSystemView : array<string|int, mixed>|null

Current system view config (or null)

$dirtyFilters : bool

Whether user explicitly modified filters

Return values
SelectQuery

The filtered query

applyHiddenStateVisibility()

Apply hidden-state visibility constraints to a recommendations query.

protected applyHiddenStateVisibility(SelectQuery $query, bool $canViewHidden) : SelectQuery

Delegate to RecommendationQueryService::applyHiddenStateVisibility() instead.

Parameters
$query : SelectQuery

Recommendations query

$canViewHidden : bool

Whether hidden rows may be included

Return values
SelectQuery

applyStateFilterOptionsToGridResult()

Inject dynamic state filter options into a Dataverse grid result payload.

protected applyStateFilterOptionsToGridResult(array<string|int, mixed> $result, bool $canViewHidden) : array<string|int, mixed>
Parameters
$result : array<string|int, mixed>

Dataverse grid processing result.

$canViewHidden : bool

Whether hidden states should be included.

Return values
array<string|int, mixed>

Updated grid result with state filter options in metadata and gridState.

appSettingImageDataUri()

Resolve shared tenant branding for the online and cached mobile templates.

protected appSettingImageDataUri(string $settingName) : string|null
Parameters
$settingName : string
Return values
string|null

assertSafeContextUrl()

Ensure URL is same-origin relative path + query only.

protected assertSafeContextUrl(string $url) : string
Parameters
$url : string
Tags
throws
BadRequestException
Return values
string

authorizeCurrentUrl()

Authorize the current URL/action via Authorization component.

protected authorizeCurrentUrl() : void
Tags
throws
ForbiddenException

When authorization fails

buildDataverseGridSearchCondition()

Build a search condition for one Dataverse grid column.

protected buildDataverseGridSearchCondition(string $field, array<string, mixed>|null $columnMeta, string $searchTerm) : array<string, mixed>|null
Parameters
$field : string

Fully-qualified database field.

$columnMeta : array<string, mixed>|null

Column metadata, when available.

$searchTerm : string

User-entered search term.

Return values
array<string, mixed>|null

buildDataverseGridState()

Build complete grid state object (single source of truth)

protected buildDataverseGridState(mixed $currentView, array<string|int, mixed>|null $selectedSystemView, array<string|int, mixed>|null $systemViews, iterable<string|int, mixed> $availableViews, Member|null $currentMember, string|int|null $preferredViewId, string $search, array<string|int, mixed> $filters, array<string|int, mixed> $filterOptions, array<string|int, mixed> $dropdownFilterColumns, array<string|int, mixed> $dateRangeFilterColumns, array<string|int, mixed> $sort, array<string|int, mixed> $visibleColumns, array<string|int, mixed> $allColumns, string $gridKey, int $pageSize, bool $showAllTab, bool $canAddViews, bool $canFilter, bool $hasSearch, bool $hasDropdownFilters, bool $hasDateRangeFilters, array<string|int, mixed> $skipFilterColumns, bool $canExportCsv, bool $showFilterPills, bool $showViewTabs, bool $enableColumnPicker[, array<string|int, mixed> $lockedFilters = [] ][, bool $enableBulkSelection = false ][, array<string|int, mixed> $bulkSelection = [] ][, array<string|int, mixed> $bulkActions = [] ][, array<string|int, mixed> $bulkSelectionDataFields = [] ][, string|null $bulkSelectionDisabledField = null ][, bool $bulkSelectionHideDisabledControl = false ][, bool $includeViewMetadata = true ][, bool $includeAllColumns = true ]) : array<string|int, mixed>
Parameters
$currentView : mixed

Current saved view entity (null for system views or "All")

$selectedSystemView : array<string|int, mixed>|null

Currently selected system view

$systemViews : array<string|int, mixed>|null

All available system views

$availableViews : iterable<string|int, mixed>

Collection of saved views

$currentMember : Member|null

Authenticated member

$preferredViewId : string|int|null

Preferred view ID from user preferences

$search : string

Current search term

$filters : array<string|int, mixed>

Active filters by column key

$filterOptions : array<string|int, mixed>

Available filter options by column key

$dropdownFilterColumns : array<string|int, mixed>

Metadata for filterable columns

$dateRangeFilterColumns : array<string|int, mixed>
$sort : array<string|int, mixed>

Current sort configuration

$visibleColumns : array<string|int, mixed>

Array of visible column keys

$allColumns : array<string|int, mixed>

Complete column metadata

$gridKey : string

Unique grid identifier

$pageSize : int

Number of rows per page

$showAllTab : bool

Whether to show "All" tab

$canAddViews : bool

Whether users can create custom views

$canFilter : bool

Whether filtering is enabled

$hasSearch : bool
$hasDropdownFilters : bool
$hasDateRangeFilters : bool
$skipFilterColumns : array<string|int, mixed>

Columns with filter UI but not query application

$canExportCsv : bool

Whether CSV export button is shown

$showFilterPills : bool

Whether active filter pills/badges are displayed

$showViewTabs : bool

Whether view tabs are displayed

$enableColumnPicker : bool

Whether column picker is available

$lockedFilters : array<string|int, mixed> = []

Filter column keys that cannot be removed by users

$enableBulkSelection : bool = false
$bulkSelection : array<string|int, mixed> = []

Bulk selection accessibility label configuration

$bulkActions : array<string|int, mixed> = []
$bulkSelectionDataFields : array<string|int, mixed> = []
$bulkSelectionDisabledField : string|null = null
$bulkSelectionHideDisabledControl : bool = false
$includeViewMetadata : bool = true
$includeAllColumns : bool = true
Return values
array<string|int, mixed>

Complete grid state

buildExportDataFromEntities()

Build export data from pre-processed entities (Data Mode)

protected buildExportDataFromEntities(iterable<string|int, mixed> $data, array<string|int, mixed> $visibleColumns, array<string|int, mixed> $columnsMetadata) : array<string|int, mixed>

Extracts values from entities using column metadata configuration. Supports virtual properties, nested relations via renderField, and custom exportValue callbacks.

Parameters
$data : iterable<string|int, mixed>

Pre-processed entities or arrays

$visibleColumns : array<string|int, mixed>

List of visible column keys

$columnsMetadata : array<string|int, mixed>

Column configuration metadata

Return values
array<string|int, mixed>

Transformed data ready for CSV export

buildExportDataFromQuery()

Build export data from database query (Query Mode)

protected buildExportDataFromQuery(Query $query, array<string|int, mixed> $visibleColumns, array<string|int, mixed> $columnsMetadata, string $tableName) : array<string|int, mixed>

Builds SQL SELECT statements and executes query for simple database fields. Best for exports that don't require computed fields.

Parameters
$query : Query

Database query to execute

$visibleColumns : array<string|int, mixed>

List of visible column keys

$columnsMetadata : array<string|int, mixed>

Column configuration metadata

$tableName : string

Full table name for model alias extraction

Return values
array<string|int, mixed>

Transformed data ready for CSV export

buildGatheringsExportValue()

Build gatherings export text showing combined recommendation events and member attendance.

protected buildGatheringsExportValue(Recommendation $recommendation[, array<string|int, mixed> $attendanceGatherings = [] ]) : string

Attendance gatherings are marked with a text suffix to replace the UI icon.

Parameters
$recommendation : Recommendation

The recommendation entity

$attendanceGatherings : array<string|int, mixed> = []

Optional array of gatherings from member attendance

Return values
string

Text string with gathering information for exports

buildGatheringsHtml()

Build gatherings HTML showing combined recommendation events and member attendance.

protected buildGatheringsHtml(Recommendation $recommendation[, array<string|int, mixed> $attendanceGatherings = [] ]) : string

Displays up to 3 gatherings with a "more" link to expand if there are more. Attendance gatherings (from GatheringAttendances with share_with_crown or share_with_kingdom) are shown with a person-check icon to distinguish from recommendation-linked events.

Parameters
$recommendation : Recommendation

The recommendation entity

$attendanceGatherings : array<string|int, mixed> = []

Optional array of gatherings from member attendance

Return values
string

HTML string with gathering information

buildGridDataUrlFromPageContext()

Build grid-data URL preserving query string from page context.

protected buildGridDataUrlFromPageContext(string|null $pageContextUrl, array<string, mixed> $gridDataRoute) : string
Parameters
$pageContextUrl : string|null
$gridDataRoute : array<string, mixed>

Cake URL array for gridData action

Return values
string

buildNotesHtml()

Build notes HTML for recommendation with popover showing all notes

protected buildNotesHtml(Recommendation $recommendation) : string

Displays note count with a popover button that shows all notes when clicked.

Parameters
$recommendation : Recommendation

The recommendation entity

Return values
string

HTML string with notes count and popover

buildOpLinksHtml()

Build OP (Order of Precedence) links HTML for a recommendation

protected buildOpLinksHtml(Recommendation $recommendation) : string
Parameters
$recommendation : Recommendation

The recommendation entity

Return values
string

HTML string with OP links

buildReasonHtml()

Build reason HTML with popover for full text if it exceeds 50 characters

protected buildReasonHtml(Recommendation $recommendation) : string

Uses Bootstrap popover to show full text without expanding the column.

Parameters
$recommendation : Recommendation

The recommendation entity

Return values
string

HTML string with reason, truncated with popover if needed

consumeFlashForStream()

Read flash from session and clear it for stream rendering.

protected consumeFlashForStream() : array<string, mixed>
Return values
array<string, mixed>

convertDateBoundaryToUtc()

Convert a date boundary string from kingdom timezone to UTC for SQL comparison.

protected convertDateBoundaryToUtc(string $dateValue, bool $isStart) : string

The database stores datetimes in UTC. Date-range filters use kingdom-timezone dates (e.g., "today" = 2026-04-09 in US/Eastern). Without conversion, a SQL comparison like start_on <= '2026-04-09 23:59:59' would miss records stored as '2026-04-10 03:00:00' UTC (which is still April 9 in Eastern).

Parameters
$dateValue : string

Date string (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)

$isStart : bool

True for start-of-day boundary (00:00:00), false for end-of-day (23:59:59)

Return values
string

UTC datetime string for SQL comparison

dispatchWorkflowEvent()

Fire a workflow event without fallback. Silently logs on failure.

protected dispatchWorkflowEvent(TriggerDispatcher $dispatcher, string $triggerEvent, array<string|int, mixed> $context) : void

Includes kingdom context from the authenticated user.

Parameters
$dispatcher : TriggerDispatcher

Workflow trigger dispatcher

$triggerEvent : string

Event name for the workflow engine

$context : array<string|int, mixed>

Event data / context for the workflow

dispatchWorkflowOrFail()

Dispatch to the workflow engine and fail when no active definition is available.

protected dispatchWorkflowOrFail(TriggerDispatcher $dispatcher, string $slug, string $triggerEvent, array<string|int, mixed> $context) : array<int, mixed>

Resolves the current kingdom from the authenticated user's branch hierarchy and includes it in the dispatch context.

Parameters
$dispatcher : TriggerDispatcher

Workflow trigger dispatcher

$slug : string

Workflow definition slug

$triggerEvent : string

Event name for the workflow engine

$context : array<string|int, mixed>

Event data / context for the workflow

Return values
array<int, mixed>

enablePluginViewCellsForFragment()

Include route-matched plugin cells in an AJAX or other fragment response.

protected enablePluginViewCellsForFragment() : void

extractContextValue()

Extract a matching value from the workflow context or its nested payload arrays.

protected extractContextValue(array<string, mixed> $context, array<int, string> $keys) : mixed
Parameters
$context : array<string, mixed>

Workflow trigger context.

$keys : array<int, string>

Keys to search for.

extractExportValue()

Extract export value from entity using column metadata

protected extractExportValue(mixed $entity, string $columnKey, array<string|int, mixed> $columnMeta) : string

Resolution order:

  1. exportValue callback if defined in column metadata
  2. renderField path for nested entity access (e.g., 'member.name_for_herald')
  3. Direct property access using column key
Parameters
$entity : mixed

Entity or array to extract value from

$columnKey : string

Column key identifier

$columnMeta : array<string|int, mixed>

Column metadata configuration

Return values
string

Extracted and formatted value

extractFilterFromExpression()

Recursively extract a filter value from an expression tree

protected extractFilterFromExpression(array<string|int, mixed> $expression, string $columnKey) : mixed
Parameters
$expression : array<string|int, mixed>

The expression node to search

$columnKey : string

The column key to find

Return values
mixed

The filter value or null if not found

extractFilterFromSystemView()

Extract a specific filter value from a system view configuration

protected extractFilterFromSystemView(array<string|int, mixed> $systemView, string $columnKey) : mixed
Parameters
$systemView : array<string|int, mixed>

The system view configuration

$columnKey : string

The column key to find

Return values
mixed

The filter value or null if not found

extractFilterFromViewConfig()

Extract a specific filter value from a saved user view's config

protected extractFilterFromViewConfig(mixed $view, string $columnKey) : mixed
Parameters
$view : mixed

The GridView entity

$columnKey : string

The column key to find

Return values
mixed

The filter value or null if not found

extractFilterGrouping()

Extract filter grouping information from expression tree

protected extractFilterGrouping(array<string|int, mixed>|null $selectedSystemView, array<string|int, mixed> $skipFilterColumns) : array<string|int, mixed>

Analyzes the expression tree to determine OR relationships between filters. Returns metadata that the frontend can use to display visual OR indicators.

Parameters
$selectedSystemView : array<string|int, mixed>|null

Currently active system view

$skipFilterColumns : array<string|int, mixed>

Columns that show as pills but don't query

Return values
array<string|int, mixed>

Grouping metadata with 'orGroups' array

extractLockedDateRangeDefaults()

Extract canonical bounds for active date-range filters whose fields are locked.

protected extractLockedDateRangeDefaults(array<string, mixed> $viewConfig, array<int, string> $lockedFilters, array<string, array<string, mixed>> $columnsMetadata) : array<string, array{value: string|null, operator: string}>
Parameters
$viewConfig : array<string, mixed>

Active system or saved-view config.

$lockedFilters : array<int, string>

Locked filter keys.

$columnsMetadata : array<string, array<string, mixed>>

Grid column metadata.

Return values
array<string, array{value: string|null, operator: string}>

Date parameter bounds.

extractNumericContextValue()

Extract a numeric value from top-level or nested workflow context arrays.

protected extractNumericContextValue(array<string, mixed> $context, array<int, string> $keys) : int|null
Parameters
$context : array<string, mixed>

Workflow trigger context.

$keys : array<int, string>

Keys to search for.

Return values
int|null

extractStringContextValue()

Extract a string value from top-level or nested workflow context arrays.

protected extractStringContextValue(array<string, mixed> $context, array<int, string> $keys) : string|null
Parameters
$context : array<string, mixed>

Workflow trigger context.

$keys : array<int, string>

Keys to search for.

Return values
string|null

extractSystemViewDefaults()

Extract default filters/search metadata for a system view configuration

protected extractSystemViewDefaults(array<string, mixed> $systemViewConfig) : array{filters: array, dateRange: array, dateRangeOperators: array, search: ?string, skipFilterColumns: array}
Parameters
$systemViewConfig : array<string, mixed>

Raw system view config

Return values
array{filters: array, dateRange: array, dateRangeOperators: array, search: ?string, skipFilterColumns: array}

formatExportValue()

Format value for CSV export

protected formatExportValue(mixed $value) : string

Handles various data types and converts to string representation.

Parameters
$value : mixed

Value to format

Return values
string

Formatted string value

getMemberAttendanceGatherings()

Fetch gatherings where members are attending with share_with_crown or share_with_kingdom enabled.

protected getMemberAttendanceGatherings(iterable<string|int, mixed> $recommendations) : array<int, array<string|int, Gathering>>

Retrieves attendance records for all unique member_ids in the recommendations set and returns a map of member_id => array of gathering entities.

Parameters
$recommendations : iterable<string|int, mixed>

Collection of recommendation entities

Return values
array<int, array<string|int, Gathering>>

Map of member_id to gatherings array

getPageContextUrl()

Posted page context URL (path + query), validated.

protected getPageContextUrl() : string|null
Return values
string|null

handleCsvExport()

Handle CSV export from grid result

protected handleCsvExport(array<string|int, mixed> $result, CsvExportService $csvExportService, string $entityName[, string|null $tableName = null ][, iterable<string|int, mixed>|null $data = null ]) : Response

Generates a CSV export response from the grid processing result. Supports two modes:

  1. Query Mode (default): Uses the query from result to build SQL SELECT statements. Best for simple fields that map directly to database columns.

  2. Data Mode: Pass pre-processed data with computed/virtual fields already populated. Best for exports that include calculated fields, virtual properties, or complex transformations that can't be done in SQL.

Column Value Resolution (in order of precedence):

  1. exportValue callback in column metadata - custom formatting function
  2. renderField path (e.g., 'member.name_for_herald') - for nested entity access
  3. queryField for relation columns in query mode
  4. Direct column key access on entity/array
Parameters
$result : array<string|int, mixed>

Result from processDataverseGrid() with isCsvExport flag

$csvExportService : CsvExportService

CSV export service instance

$entityName : string

Base name for the export file (e.g., 'members', 'warrants')

$tableName : string|null = null

Optional table name for fetchTable (e.g., 'Awards.Recommendations' for plugin tables) If not provided, uses ucfirst($entityName)

$data : iterable<string|int, mixed>|null = null

Optional pre-processed data. If provided, uses data mode instead of query mode. Data should be an iterable of entities or arrays with all computed fields populated.

Tags
throws
ForbiddenException

If user lacks export permission

Return values
Response

CSV download response

isCsvExportRequest()

Check if the current request is for CSV export

protected isCsvExportRequest() : bool
Return values
bool

True if CSV export is requested

isDataverseTableFrameRequest()

protected isDataverseTableFrameRequest() : bool
Return values
bool

Whether request is for inner table frame.

isGridOriginRequest()

Whether POST originated from a grid index (stay on list).

protected isGridOriginRequest(string|null $pageContextUrl) : bool
Parameters
$pageContextUrl : string|null
Return values
bool

loadAvailableViews()

Load and cache available views for the current request.

protected loadAvailableViews(string $gridKey, int $memberId) : array<int, mixed>
Parameters
$gridKey : string

Grid identifier

$memberId : int

Authenticated member id

Return values
array<int, mixed>

loadFilterOptions()

Load filter options from a data source

protected loadFilterOptions(array<string|int, mixed>|string $source) : array<string|int, mixed>

Supports multiple formats for filterOptionsSource:

  1. Simple string (table name): Uses 'id' for value, 'name' for label

    'filterOptionsSource' => 'Branches'
    
  2. Array with table: Database table with full control

    'filterOptionsSource' => [
        'table' => 'Waivers.WaiverTypes',  // Required: table name for fetchTable()
        'valueField' => 'id',              // Optional: field for option value (default: 'id')
        'labelField' => 'name',            // Optional: field for option label (default: 'name')
        'conditions' => ['is_active' => true],  // Optional: filter conditions
        'order' => ['name' => 'ASC'],      // Optional: sort order (default: labelField ASC)
    ]
    
  3. Array with appSetting: Load from app settings (YAML array)

    'filterOptionsSource' => [
        'appSetting' => 'Branches.Types',  // Required: app setting key
    ]
    

    The app setting should contain a YAML array like: ['Kingdom', 'Principality', 'Barony'] Both value and label will be set to the array item value.

  4. Array with method: Call a static method on a class to get options

    'filterOptionsSource' => [
        'method' => 'getGatheringsFilterOptions',  // Required: static method name
        'class' => 'Awards\\KMP\\GridColumns\\RecommendationsGridColumns',  // Required: fully qualified class name
    ]
    

    The method should return array of ['value' => string, 'label' => string].

Parameters
$source : array<string|int, mixed>|string

Source identifier string (table name) or configuration array

Return values
array<string|int, mixed>

Filter options as array of ['value' => string, 'label' => string]

loadFilterOptionsCached()

Load filter options with per-request cache.

protected loadFilterOptionsCached(array<string|int, mixed>|string $source) : array<int, array{value: string, label: string}>
Parameters
$source : array<string|int, mixed>|string

filterOptionsSource configuration

Return values
array<int, array{value: string, label: string}>

matchesGridIndexPath()

Whether page context path matches a grid index route pattern.

protected matchesGridIndexPath(string|null $pageContextUrl, string $pathRegex) : bool
Parameters
$pageContextUrl : string|null
$pathRegex : string
Return values
bool

mobileQueuePagination()

Build shared pagination values for mobile actionable queues.

protected mobileQueuePagination(int $total) : array<string, int|bool>
Parameters
$total : int

Total actionable records

Return values
array<string, int|bool>

mobileQueuePaginationPayload()

Remove internal pagination values before sending the mobile JSON payload.

protected mobileQueuePaginationPayload(array<string, int|bool> $pagination) : array<string, int|bool>
Parameters
$pagination : array<string, int|bool>

Pagination data

Return values
array<string, int|bool>

operationCategorySummary()

Build a plain-text summary from trusted category labels and their counts.

protected operationCategorySummary(array<string, int> $categoryCounts, string $label) : string
Parameters
$categoryCounts : array<string, int>

Counts keyed by static, user-safe labels.

$label : string

User-facing summary label.

Return values
string

Empty when every count is zero.

operationReasonSummary()

Build a bounded, plain-text count of operational result reasons.

protected operationReasonSummary(array<string|int, mixed> $entries, string $label) : string
Parameters
$entries : array<string|int, mixed>

Result entries containing a reason.

$label : string

User-facing summary label.

Return values
string

Empty when no usable reasons were supplied.

organizeViewCells()

Organize view cells by type and display order.

protected organizeViewCells(array<string|int, mixed> $viewCells) : array<string|int, mixed>

Unused - view cells organized in ViewCellRegistry

Parameters
$viewCells : array<string|int, mixed>

Flat array of view cell configurations

Return values
array<string|int, mixed>

Organized array grouped by type and sorted by order

prepareRecommendationsForExport()

Prepare recommendations for CSV export with computed fields

protected prepareRecommendationsForExport(Query $query[, array<string|int, mixed> $options = [] ]) : iterable<string|int, mixed>

Fetches all data from the query (not paginated) and populates computed fields that can't be calculated via SQL (virtual properties, formatted strings, etc.)

Parameters
$query : Query

The filtered query from processDataverseGrid

$options : array<string|int, mixed> = []

Export options (includeAttendance => bool)

Return values
iterable<string|int, mixed>

Recommendations with computed fields populated

processDataverseGrid()

Process dataverse grid request with unified logic

protected processDataverseGrid(array<string|int, mixed> $config) : array<string|int, mixed>

This method handles all aspects of grid processing including view management, filtering, searching, sorting, and pagination. It supports both saved user views and system-defined views.

Parameters
$config : array<string|int, mixed>

Grid configuration with the following keys:

  • gridKey (string): Unique identifier for the grid
  • gridColumnsClass (string): Fully qualified class name for grid columns metadata
  • baseQuery (Query): Base query object to start with
  • tableName (string): Primary table name for field qualification
  • defaultSort (array): Default sort configuration ['field' => 'direction']
  • defaultPageSize (int): Default number of records per page (default: 25)
  • systemViews (array|null): Optional array of system views (for Warrants-style grids)
  • defaultSystemView (string|null): Default system view key (required if systemViews provided)
  • queryCallback (callable|null): Optional callback to modify query per system view
  • showAllTab (bool): Whether to show "All" tab (default: true for saved views, false for system views)
  • canAddViews (bool): Whether users can create custom views (default: true)
  • canFilter (bool): Whether user filtering is enabled (default: true). When false, users cannot add/remove filters via the UI or query parameters. However, filters defined by system views are ALWAYS applied regardless of this setting.
  • canExportCsv (bool): Whether CSV export button is shown (default: true)
  • showFilterPills (bool): Whether active filter pills/badges are displayed (default: true)
  • showViewTabs (bool): Whether view tabs are displayed (default: true)
  • enableColumnPicker (bool): Whether column picker is available (default: true)
  • lockedFilters (array): Array of filter column keys that cannot be removed by users. Locked filters will not show remove (×) buttons and their values cannot be cleared via query string parameters. Useful for embedded grids where context filters (e.g., member_id) must always be applied.
  • enableBulkSelection (bool): Whether row selection checkboxes are shown (default: false)
  • bulkSelection (array): Bulk selection accessibility label configuration. Keys: selectAllLabel, rowLabelTemplate, disabledLabel. rowLabelTemplate supports {field_key} placeholders resolved from each row, including dotted paths and column renderField aliases.
  • bulkActions (array): Array of bulk action button configurations when enableBulkSelection is true. Each action is an array with keys: label, icon, modalTarget, permission.
  • disablePagination (bool): When true, bypasses the paginator and returns all matching records. Use for views (e.g. calendar) that are already filtered to a bounded date range and must show every result without an arbitrary row cap. Caller responsibility*: the baseQuery MUST include WHERE clauses that bound the result set (e.g. a date range) to avoid fetching unbounded data. (default: false)

NOTE: Authorization scope must be applied to baseQuery BEFORE calling this method. Use $baseQuery = $this->Authorization->applyScope($baseQuery, 'index'); in your controller before passing the query to processDataverseGrid().

Return values
array<string|int, mixed>

Result array with keys: data, gridState, columnsMetadata, etc.

renderDataverseGridResponse()

Render consistent dataverse grid responses for outer/table turbo frames.

protected renderDataverseGridResponse(array<string, mixed> $result, string $frameId[, string|null $collectionVar = null ][, array<string, mixed> $extraViewVars = [] ]) : void
Parameters
$result : array<string, mixed>

processDataverseGrid() result

$frameId : string

Outer frame id (e.g. members-grid)

$collectionVar : string|null = null

Optional collection variable name to set (e.g. members)

$extraViewVars : array<string, mixed> = []

Additional vars to expose to template

renderDataverseTableRowElement()

Render a single Dataverse grid row element (Turbo Stream replace target HTML).

protected renderDataverseTableRowElement(array<string, mixed> $vars) : string
Parameters
$vars : array<string, mixed>

Element variables

Return values
string

renderTurboCloseModal()

Render turbo-stream: flash + replace table frame with lazy reload src.

protected renderTurboCloseModal(string $refreshFrame, array<string, mixed> $gridDataRoute[, string|null $pageContextUrl = null ][, array<string|int, mixed>|null $flashMessages = null ]) : Response
Parameters
$refreshFrame : string
$gridDataRoute : array<string, mixed>
$pageContextUrl : string|null = null
$flashMessages : array<string|int, mixed>|null = null
Return values
Response

renderTurboFlashOnly()

Render turbo-stream flash messages without forcing a grid or frame reload.

protected renderTurboFlashOnly([array<string|int, mixed>|null $flashMessages = null ]) : Response
Parameters
$flashMessages : array<string|int, mixed>|null = null
Return values
Response

renderTurboReloadFrame()

Stream that reloads an edit turbo-frame (validation errors).

protected renderTurboReloadFrame(string $frameId, string $frameSrc[, array<string|int, mixed>|null $flashMessages = null ]) : Response
Parameters
$frameId : string
$frameSrc : string
$flashMessages : array<string|int, mixed>|null = null
Return values
Response

renderTurboRemoveGridRow()

Render turbo-stream: flash + remove a grid row (no longer matches current filters).

protected renderTurboRemoveGridRow(string $rowDomId[, array<string|int, mixed>|null $flashMessages = null ]) : Response
Parameters
$rowDomId : string
$flashMessages : array<string|int, mixed>|null = null
Return values
Response

renderTurboReplaceGridRow()

Render turbo-stream: flash + replace a single grid row by DOM id.

protected renderTurboReplaceGridRow(string $rowDomId, string $rowHtml[, array<string|int, mixed>|null $flashMessages = null ]) : Response
Parameters
$rowDomId : string
$rowHtml : string
$flashMessages : array<string|int, mixed>|null = null
Return values
Response

resolveBranchIdFromContextMember()

Resolve a branch ID from member identifiers carried in workflow context.

protected resolveBranchIdFromContextMember(array<string, mixed> $context) : int|null

Supports both direct member IDs and member public IDs from public forms.

Parameters
$context : array<string, mixed>

Workflow trigger context.

Return values
int|null

resolveDataverseGridQueryContext()

Resolve Dataverse grid column context for early query construction.

protected resolveDataverseGridQueryContext(array<string, mixed> $config[, array<string, mixed>|null $selectedSystemView = null ][, mixed $currentView = null ][, bool $viewContextResolved = false ]) : DataverseGridQueryContext
Parameters
$config : array<string, mixed>

Grid configuration.

$selectedSystemView : array<string, mixed>|null = null

Already-resolved system view when called from processDataverseGrid().

$currentView : mixed = null

Already-resolved saved view when called from processDataverseGrid().

$viewContextResolved : bool = false

Whether null selected/current view values are already authoritative.

Return values
DataverseGridQueryContext

resolveKingdomId()

Resolve the kingdom ID from the authenticated member or workflow context.

protected resolveKingdomId([array<string, mixed> $context = [] ]) : int|null

Authenticated requests still prefer the actor's branch ancestry. Anonymous requests can derive kingdom from explicit branch or member identifiers in the workflow context so public forms can dispatch to kingdom-specific flows.

Parameters
$context : array<string, mixed> = []

Workflow trigger context.

Return values
int|null

Kingdom branch ID, or null if unavailable

resolveKingdomIdFromBranch()

Walk the branch parent chain to find the kingdom-type ancestor.

protected resolveKingdomIdFromBranch(int $branchId) : int|null
Parameters
$branchId : int

Starting branch ID

Return values
int|null

Kingdom branch ID, or null if no kingdom found

resolveNestedValue()

Resolve nested value from entity using dot notation path

protected resolveNestedValue(mixed $entity, string $path) : mixed
Parameters
$entity : mixed

Entity to traverse

$path : string

Dot-notation path (e.g., 'member.name_for_herald')

Return values
mixed

Resolved value or null if path doesn't exist

wantsTurboStreamRequest()

Whether the client expects a turbo-stream response.

protected wantsTurboStreamRequest() : bool
Return values
bool

withPageContextQuery()

Run a callback with query params from the posted page context URL.

protected withPageContextQuery(string|null $pageContextUrl, callable(): T $callback) : T
Parameters
$pageContextUrl : string|null
$callback : callable(): T
Tags
template
Return values
T

appendActiveRecommendationColumns()

private appendActiveRecommendationColumns(array<int, string> $columns) : array<int, string>
Parameters
$columns : array<int, string>
Return values
array<int, string>

applyDataverseGridSort()

Apply a standard field sort or delegate to a column-specific sort handler.

private applyDataverseGridSort(SelectQuery $query, string $columnKey, string $direction, array<string, mixed> $columnMeta, string $tableName) : SelectQuery

Custom handlers are useful when a relation sort needs a correlated subquery or another expression that remains valid in paginator/eager-loader subqueries.

Parameters
$query : SelectQuery

Query being sorted.

$columnKey : string

Grid column key.

$direction : string

Requested sort direction.

$columnMeta : array<string, mixed>

Column metadata.

$tableName : string

Primary query alias.

Return values
SelectQuery

Sorted query.

approvalRequiresBestowalGatheringSelection()

Determine whether this recommendation approval must schedule the created bestowal.

private approvalRequiresBestowalGatheringSelection(WorkflowApproval|null $approval, array<string, mixed> $approverConfig) : bool

Older pending approvals may predate requires_bestowal_gathering in node config, so the award workflow slug remains the compatibility fallback.

Parameters
$approval : WorkflowApproval|null

Approval.

$approverConfig : array<string, mixed>

Approval config.

Return values
bool

augmentApproverConfigForResponse()

private augmentApproverConfigForResponse(array<string, mixed> $approverConfig[, WorkflowApproval|null $approval = null ][, Recommendation|null $recommendation = null ]) : array<string, mixed>
Parameters
$approverConfig : array<string, mixed>

Approval config.

$approval : WorkflowApproval|null = null
$recommendation : Recommendation|null = null
Return values
array<string, mixed>

awardApprovalFinalStepState()

private awardApprovalFinalStepState(WorkflowApproval $approval, array<string, mixed> $approverConfig) : bool|null
Parameters
$approval : WorkflowApproval

Approval.

$approverConfig : array<string, mixed>

Approval config.

Return values
bool|null

canViewLinkedBestowal()

Check whether the current identity can view the linked bestowal for a recommendation row.

private canViewLinkedBestowal(Recommendation $recommendation, mixed $identity) : bool
Parameters
$recommendation : Recommendation

Recommendation row.

$identity : mixed

Current identity.

Return values
bool

collectDataverseExpressionColumnKeys()

private collectDataverseExpressionColumnKeys(mixed $expression, array<int, string> &$columns) : void
Parameters
$expression : mixed
$columns : array<int, string>

columnKeyForDataverseField()

private columnKeyForDataverseField(string $field, array<string, array<string, mixed>> $columnsMetadata) : string
Parameters
$field : string
$columnsMetadata : array<string, array<string, mixed>>
Return values
string

decoratePendingWorkflowApprovals()

Add current-user pending approval metadata for recommendation grid actions.

private decoratePendingWorkflowApprovals(iterable<string|int, Recommendation$recommendations) : void
Parameters
$recommendations : iterable<string|int, Recommendation>

Recommendations to decorate.

defaultRecommendationVisibleColumns()

private defaultRecommendationVisibleColumns() : array<int, string>
Return values
array<int, string>

dispatchRecommendationFollowUpWorkflow()

Dispatch a post-commit workflow event returned by the recommendation mutation.

private dispatchRecommendationFollowUpWorkflow(TriggerDispatcher $triggerDispatcher, array<string, mixed> $result, int $actorId) : void
Parameters
$triggerDispatcher : TriggerDispatcher

Workflow trigger dispatcher.

$result : array<string, mixed>

Normalized recommendation mutation result.

$actorId : int

Actor ID.

dispatchRecommendationMutation()

Dispatch a workflow-backed recommendation mutation and normalize its result.

private dispatchRecommendationMutation(TriggerDispatcher $triggerDispatcher, string $slug, string $triggerEvent, array<string, mixed> $context) : Recommendation}
Parameters
$triggerDispatcher : TriggerDispatcher

Workflow dispatcher.

$slug : string

Workflow definition slug.

$triggerEvent : string

Workflow trigger event name.

$context : array<string, mixed>

Workflow context payload.

Return values
Recommendation}

enrichRecommendationsForGrid()

Add computed display fields used by the recommendations Dataverse grid.

private enrichRecommendationsForGrid(iterable<string|int, Recommendation$recommendations[, array<string|int, mixed> $visibleColumns = [] ]) : void
Parameters
$recommendations : iterable<string|int, Recommendation>
$visibleColumns : array<string|int, mixed> = []

extractDataverseGridConfigColumnKeys()

private extractDataverseGridConfigColumnKeys(array<string, mixed> $config) : array<int, string>
Parameters
$config : array<string, mixed>
Return values
array<int, string>

extractRecommendationIdFromResult()

Extract the saved recommendation ID from a normalized mutation result.

private extractRecommendationIdFromResult(array{data?: array, recommendation?: mixed} $result) : int|null
Parameters
$result : array{data?: array, recommendation?: mixed}

Normalized mutation result.

Return values
int|null

filterRecommendationGridActionsForResult()

private filterRecommendationGridActionsForResult(array<string, mixed> $gridResult) : array<string, mixed>
Parameters
$gridResult : array<string, mixed>
Return values
array<string, mixed>

filterRecommendationRowActionsForGridResult()

private filterRecommendationRowActionsForGridResult(array<string, array<string, mixed>> $rowActions, array<string, mixed> $gridResult) : array<string, array<string, mixed>>
Parameters
$rowActions : array<string, array<string, mixed>>
$gridResult : array<string, mixed>
Return values
array<string, array<string, mixed>>

getPendingApprovalsForMember()

private getPendingApprovalsForMember(int $memberId, array<string|int, int> $approvalIds) : array<int, WorkflowApproval>
Parameters
$memberId : int

Member ID.

$approvalIds : array<string|int, int>

Approval IDs.

Return values
array<int, WorkflowApproval>

isArchivedRecommendationResult()

Check the semantic archived filter so copied views keep archived-only actions.

private isArchivedRecommendationResult(array<string, mixed> $gridResult) : bool
Parameters
$gridResult : array<string, mixed>

Processed grid result.

Return values
bool

Whether the result is scoped to archived recommendations.

isDataverseGridNumericSearchColumn()

private isDataverseGridNumericSearchColumn(array<string, mixed>|null $columnMeta) : bool
Parameters
$columnMeta : array<string, mixed>|null

Column metadata.

Return values
bool

isRecommendationColumnVisible()

Determine whether a recommendation column should be treated as visible.

private isRecommendationColumnVisible(string $columnKey[, array<int, string> $visibleColumns = [] ]) : bool
Parameters
$columnKey : string
$visibleColumns : array<int, string> = []
Return values
bool

isSelectableBestowalGathering()

private isSelectableBestowalGathering(int $gatheringId) : bool
Parameters
$gatheringId : int

Gathering ID.

Return values
bool

isSelectableBestowalGatheringForRecommendation()

private isSelectableBestowalGatheringForRecommendation(Recommendation $recommendation, int $gatheringId) : bool
Parameters
$recommendation : Recommendation

Recommendation context.

$gatheringId : int

Gathering ID.

Return values
bool

isWorkflowDispatchResult()

Determine whether the result is a list of workflow engine service results.

private isWorkflowDispatchResult(array<int, mixed> $result) : bool
Parameters
$result : array<int, mixed>

Result payload to inspect.

Return values
bool

loadRecommendationGridViewColumns()

private loadRecommendationGridViewColumns(string $gridKey, int $viewId, int|null $memberId) : array<int, string>|null
Parameters
$gridKey : string

Grid identifier.

$viewId : int

Grid view id.

$memberId : int|null

Current member id.

Return values
array<int, string>|null

normalizeApproverConfig()

private normalizeApproverConfig(mixed $approverConfig) : array<string, mixed>
Parameters
$approverConfig : mixed

Approval config.

Return values
array<string, mixed>

normalizeDataverseGridColumnConfig()

private normalizeDataverseGridColumnConfig(mixed $columns) : array<int, string>
Parameters
$columns : mixed
Return values
array<int, string>

normalizeLockedDateBoundary()

Normalize a persisted date boundary while retaining an intentionally open bound.

private normalizeLockedDateBoundary(mixed $value) : string|null
Parameters
$value : mixed
Return values
string|null

normalizeRecommendationColumns()

private normalizeRecommendationColumns(array<int, mixed> $columns) : array<int, string>
Parameters
$columns : array<int, mixed>
Return values
array<int, string>

normalizeRecommendationMutationResult()

Normalize legacy service results and workflow-dispatch results to one controller shape.

private normalizeRecommendationMutationResult(mixed $result) : Recommendation}
Parameters
$result : mixed

Shared service result or workflow dispatch output.

Return values
Recommendation}

normalizeWorkflowDispatchResult()

Collapse workflow dispatch results down to the workflow end-node result payload.

private normalizeWorkflowDispatchResult(array<int, ServiceResult$results) : Recommendation}
Parameters
$results : array<int, ServiceResult>

Workflow dispatch results.

Return values
Recommendation}

pageContextQueryTab()

Tab query param from page context URL (detail pages).

private pageContextQueryTab(string|null $pageContextUrl) : string|null
Parameters
$pageContextUrl : string|null
Return values
string|null

parseIdList()

Parse comma or whitespace separated numeric IDs.

private parseIdList(string $value) : array<string|int, int>
Parameters
$value : string
Return values
array<string|int, int>

parseMemberIdList()

Parse member IDs from normal member lookup values.

private parseMemberIdList(string $value) : array<string|int, int>

The member autocomplete returns public_id values; numeric IDs are still accepted for callers that do not use the lookup control.

Parameters
$value : string
Return values
array<string|int, int>

recommendationsGridRefreshResponse()

Turbo-stream table refresh for recommendation grid actions.

private recommendationsGridRefreshResponse(string|null $pageContext) : Response|null
Parameters
$pageContext : string|null
Return values
Response|null

recordWorkflowApprovalDecision()

private recordWorkflowApprovalDecision(WorkflowApproval $approval, int $memberId, string $decision, string|null $comment, TriggerDispatcher $triggerDispatcher[, int|null $bestowalGatheringId = null ]) : ServiceResult
Parameters
$approval : WorkflowApproval

Approval entity.

$memberId : int

Approver member ID.

$decision : string

Decision value.

$comment : string|null

Optional comment.

$triggerDispatcher : TriggerDispatcher

Trigger dispatcher.

$bestowalGatheringId : int|null = null
Return values
ServiceResult

requiresBestowalGatheringSelection()

private requiresBestowalGatheringSelection(array<string, mixed> $approverConfig) : bool
Parameters
$approverConfig : array<string, mixed>

Approval config.

Return values
bool

resolveDataverseGridActiveColumns()

Resolve hidden-but-active query dependency columns.

private resolveDataverseGridActiveColumns(array<string, mixed> $config, array<string, array<string, mixed>> $columnsMetadata, array<string, mixed>|null $selectedSystemView, mixed $currentView) : array<int, string>
Parameters
$config : array<string, mixed>

Grid configuration.

$columnsMetadata : array<string, array<string, mixed>>
$selectedSystemView : array<string, mixed>|null
$currentView : mixed
Return values
array<int, string>

resolveDataverseGridViewContext()

Resolve active saved/system view enough for pre-query column dependency planning.

private resolveDataverseGridViewContext(array<string, mixed> $config) : array{selectedSystemView: array|null, currentView: mixed}
Parameters
$config : array<string, mixed>

Grid configuration.

Return values
array{selectedSystemView: array|null, currentView: mixed}

resolveDataverseGridVisibleColumns()

Resolve UI-visible columns using the same precedence as processDataverseGrid().

private resolveDataverseGridVisibleColumns(class-string $gridColumnsClass, array<string, array<string, mixed>> $columnsMetadata, array<string, mixed>|null $selectedSystemView, mixed $currentView) : array<int, string>
Parameters
$gridColumnsClass : class-string
$columnsMetadata : array<string, array<string, mixed>>
$selectedSystemView : array<string, mixed>|null
$currentView : mixed
Return values
array<int, string>

resolveRecommendationGridRowSync()

Resolve targeted row sync after a single recommendation save.

private resolveRecommendationGridRowSync(int $recommendationId, string|null $pageContextUrl, RecommendationQueryService $queryService) : array{action: string, rowDomId: string, rowHtml?: string}|null
Parameters
$recommendationId : int
$pageContextUrl : string|null
$queryService : RecommendationQueryService
Return values
array{action: string, rowDomId: string, rowHtml?: string}|null

Null → full table refresh

resolveRecommendationGridSyncContext()

Match page context to a recommendation grid row-sync context.

private resolveRecommendationGridSyncContext(string|null $pageContextUrl) : array{contextKey: string, tableFrameId: string, memberId?: int, gatheringId?: int}|null
Parameters
$pageContextUrl : string|null
Return values
array{contextKey: string, tableFrameId: string, memberId?: int, gatheringId?: int}|null

resolveRecommendationVisibleColumns()

Resolve visible columns early so recommendation queries can skip hidden display-only associations.

private resolveRecommendationVisibleColumns(string $gridKey, array<string, array<string, mixed>> $systemViews, string $defaultSystemView) : array<int, string>|null
Parameters
$gridKey : string

Grid identifier.

$systemViews : array<string, array<string, mixed>>

System view definitions.

$defaultSystemView : string

Default system view key.

Return values
array<int, string>|null

Null means all display data is required.

shouldIncludeRecommendationColumn()

Determine whether a column is requested for the current grid request.

private shouldIncludeRecommendationColumn(string $columnKey[, array<string|int, mixed>|null $visibleColumns = null ]) : bool
Parameters
$columnKey : string
$visibleColumns : array<string|int, mixed>|null = null
Return values
bool

tryRecommendationsGridTurboResponse()

Turbo-stream response for grid-origin recommendation saves.

private tryRecommendationsGridTurboResponse(string|null $pageContext, bool $success[, int|null $reloadQuickEditId = null ][, int|null $updatedRecommendationId = null ][, RecommendationQueryService|null $queryService = null ]) : Response|null
Parameters
$pageContext : string|null
$success : bool
$reloadQuickEditId : int|null = null
$updatedRecommendationId : int|null = null
$queryService : RecommendationQueryService|null = null
Return values
Response|null

validateBestowalGatheringSelection()

private validateBestowalGatheringSelection(WorkflowApproval|null $approval, string $decision, int|null $gatheringId[, Recommendation|null $recommendation = null ]) : string|null
Parameters
$approval : WorkflowApproval|null

Approval.

$decision : string

Submitted decision.

$gatheringId : int|null

Selected gathering ID.

$recommendation : Recommendation|null = null

Recommendation context.

Return values
string|null

validateWorkflowDecision()

private validateWorkflowDecision(WorkflowApproval $approval, string $decision, string $comment) : string|null
Parameters
$approval : WorkflowApproval

Approval entity.

$decision : string

Decision value.

$comment : string

Comment text.

Return values
string|null

Validation error, if any.

On this page

Search results