Issue #3621245: Declare what the views handlers read, so the shipped views can be cached without going stale
Two halves, and shipping either alone would be wrong.
The handlers. A field handler reaches a display's cacheability only by implementing CacheableDependencyInterface, which FieldPluginBase, unlike FilterPluginBase, does not. Seven columns resolve their value from something the view never queried and declared nothing:
| Handler | Read beyond the row | Now declares |
|---|---|---|
LinkedUserFieldBase (Assignee, Initiator) |
user entities |
user |
WorkItemHolder |
user entities |
user |
InstanceVariable |
variable rows, date formats | orchestra_variable, date_format |
NodeLabel |
instances and workflows | orchestra_instance, orchestra_workflow |
WorkflowLabel |
workflows | orchestra_workflow |
WorkItemOutcome |
the token's node config, from the run's workflow | orchestra_token, orchestra_workflow |
InstanceStatus (field) |
orchestra_status terms |
orchestra_status |
The three methods were the same each time, so they live in EntityListCacheTrait: a class names the entity types it reads and gets their list cache tags, no contexts, permanent max-age. CurrentStep moves onto it too, which removes the copy #3621216 added. WorkItemHolder keeps AssignmentCacheTrait and answers getCacheTags() itself, as InstanceLinkFieldBase already does, because its per-viewer half belongs on the render.
List tags rather than per-row ones: the handler answers for the whole display, and what is on the page changes as rows come and go, which a per-row tag cannot see.
Checked and left alone: InstanceState and WorkItemState render from the row entity and a static label map; the InstanceLinkFieldBase family, TaskActionLink, TaskOperations and InstanceActionLink already declare; the filters inherit cacheability from FilterPluginBase.
The exports. View::preSave() recalculates only when a view is saved through the UI or the API — never while syncing, never with trusted data, which is how ConfigInstaller saves. So the exported file is what a site runs on. All seven shipped views stored max-age: 0 and tags: { }, meaning fifteen displays that are not cached at all, and stale since the handlers first gained cacheability. Regenerated from what the fixed handlers calculate.
Test. ShippedViewCacheabilityTrait asserts, per display, that the file's max-age, contexts and tags are what the display calculates, replicating what preSave() would have written down to the merged interface-language context and the sorting. Both view modules call it. Against the unfixed tree it fails on the max-age of every display and on every tag.
Order matters here: regenerating the exports before fixing the handlers would have turned fifteen uncached displays into fifteen displays that go stale, which is why the two halves are one issue.