bug: #3571915 Filter Field Widget Action automator processing to the selected automator ID

Description

Closes #3571915 (closed).

Field Widget Actions can target a specific automator by ID, but AiAutomatorEntityModifier::saveEntity() had no way to isolate a single automator when more than one is configured on the same field (possible by duplicating an automator config with a different ID suffix — not exposed by the default UI, but not prevented either). Clicking one Field Widget Action button would run every automator configured for that field, so two buttons like Translate and Summarize on the same field would run both, or overwrite each other's output.

Changes:

  • AiAutomatorEntityModifier::saveEntity() gains an optional $specificAutomatorId parameter. When set, processing is filtered to the matching automator config entity ID before any processor runs. This filter must run before the existing usort() call, which reindexes the configs array to sequential integer keys and would otherwise silently defeat a key-based filter.
  • AutomatorFieldWidgetActionTrait::populateAutomatorValues() (used by AutomatorBaseAction) now passes the configured automator_id through to saveEntity(), and guards against saveEntity() returning NULL (no matching automator) instead of calling a method on NULL.
  • AutomatorRefinableBaseAction::generateContent() had the identical bug in the "refine" feature's content-seeding path (added after this issue was filed) — fixed the same way, with the same NULL guard.

Testing instructions

  1. Enable ai, ai_automators, and field_widget_actions.
  2. Configure two AI automators for the same field (e.g. node.article.body) by duplicating an automator config with a different ID suffix.
  3. Add both automators as Field Widget Actions on the form display.
  4. Edit a node and click one of the automator buttons.
  5. Expect: only the selected automator runs. Before this fix, all automators configured for that field would run.

Automated coverage: added testSaveEntityFiltersBySpecificAutomatorId() and testSaveEntityReturnsNullForUnmatchedAutomatorId() to TextToImageMediaFieldWidgetProcessingTest. The first creates two automators on the same field — the second deliberately misconfigured with a nonexistent rule ID, which fatally errors if ever invoked — and asserts that filtering by the first automator's ID succeeds without ever touching the second.

Checklist

  • I have linked the related issue in the MR title or description
  • I have performed a self-review of my own code
  • I have added or updated tests, or explained in the description why this change is not covered by tests
  • I have updated documentation for any new or changed functionality
  • I have written testing instructions and verified them locally
  • I have noted any required post-merge steps (config imports, cache rebuilds, manual changes)
  • This MR contains no breaking API or hook changes, or they are explicitly documented in the description

saveEntity()'s new parameter is optional and appended last, so no existing call site needs to change.

AI Compliance

Note

  • AI Generated Code
    Mainly generated by AI, reviewed and approved by a human before this MR was created.

Merge request reports

Loading