Skip to content

Add interpretation-stage events: PreInterpretFileEvent and PreQueueRowEvent - #680

Open
alexbaat wants to merge 3 commits into
pimcore:2026.xfrom
alexbaat:improvement/interpreter-stage-events
Open

Add interpretation-stage events: PreInterpretFileEvent and PreQueueRowEvent#680
alexbaat wants to merge 3 commits into
pimcore:2026.xfrom
alexbaat:improvement/interpreter-stage-events

Conversation

@alexbaat

Copy link
Copy Markdown
Contributor

Changes in this pull request

Resolves pimcore/platform-version#340

Adds two events at the interpretation stage (file → rows), so projects can adjust import rows with a small listener instead of copying a whole interpreter (all shipped interpreters are final, so today even one line of row logic means duplicating the CSV/XLSX/JSON/XML reading code, fileValid(), previewData(), setSettings(), and a Studio UI dynamic type).

PreQueueRowEvent

Dispatched in AbstractInterpreter::processImportRow() for every extracted row, before the delta check, identifier cache, and queueing — i.e. early enough that changed values (including the ID column) affect the resolver, the delta check, and the path/location strategies. Listeners can:

  • modify the row: $event->setRows([$changedRow]) — e.g. add computed key/path columns for the resolver
  • skip the row: $event->skipRow() — with skipRow(keepInCleanupIdentifierCache: true) the original row's identifier is still registered, so an active cleanup strategy does not delete/unpublish the row's existing element (an easy trap to fall into otherwise; covered in docs and tests)
  • fan out the row: $event->setRows([$rowA, $rowB, $rowC]) — each row is queued and imported as its own element (1 source row → N elements is impossible at the mapping stage by construction)

Cross-row state (e.g. SAP-style exports where a group marker row applies to all following rows) works naturally: dispatches are sequential within one interpretFile() run, and PreInterpretFileEvent doubles as a per-run reset signal.

PreInterpretFileEvent

Dispatched at the start of interpretFile() with a settable path: normalize the file (transcode, strip a report preamble, rewrite delimiters) while keeping the standard interpreter.

Studio preview parity

Both events are also dispatched (flagged isPreview()) in the preview/column-header/transformation-preview code paths via a new internal PreviewEventApplier, so the mapping UI shows exactly the columns an actual import produces — listener-added synthetic columns are visible and mappable. Skipped rows stay visible in the preview; a fan-out shows the first resulting row and exposes the columns of all resulting rows.

Wiring & BC

  • AbstractInterpreter gets a null-guarded setEventDispatcher() (constructor unchanged — no BC break for existing custom interpreters).
  • The interpreter compiler pass adds the setEventDispatcher call to every tagged interpreter service that supports it, so built-in and custom interpreters dispatch the events.
  • Without listeners, behavior is unchanged (covered by tests, including the existing CsvEncodingInterpreterTest).

Additional info

  • Follows the invitation in doc/06_Extending/02_Events.md ("More events to come when needed (just provide PRs ;-)"), which this PR also extends with full documentation of both events including the cleanup-interaction warning.
  • Complements Improve: allow PreSaveEvent listeners to skip default object persistence #607, which adds a similar skip capability at the save stage.
  • Concrete motivation: our production project ships three custom interpreters (~840 lines PHP plus a Studio UI module-federation remote) whose only purpose is row filtering, cross-row group-marker carry-forward with synthetic resolver columns, and a wide-to-long pivot (1 row → 3 elements). All three reduce to small PreQueueRowEvent listeners on the stock CSV interpreter with these events.
  • Tests: PreQueueRowEventTest (event API), InterpreterRowEventTest (end-to-end through CsvFileInterpreter + real QueueService: unchanged baseline, modify, skip, fan-out, file replacement, compiler-pass wiring), PreviewEventApplierTest (preview parity). Verified locally: unit suite green, php-cs-fixer clean, phpstan (repo config) clean.

🤖 Generated with Claude Code

…wEvent

Listeners can now normalize the source file, and modify, skip, or fan out
extracted rows before they are queued - covering row filtering, cross-row
state, synthetic resolver columns, and 1-to-N imports without writing a
custom interpreter. Both events are mirrored into the Studio preview so
the mapping UI shows the columns an actual import would produce.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings August 18, 2026 17:08
@pimcore-deployments
pimcore-deployments marked this pull request as draft August 18, 2026 17:09

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Install dependencies with Composer

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds interpretation-stage extension points to modify source files and rows without custom interpreters, addressing platform-version#340.

Changes:

  • Adds file and row events with modify, skip, cleanup-preservation, and fan-out support.
  • Integrates events into imports and Studio previews.
  • Adds documentation and regression tests.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/Event/PreInterpretFileEvent.php Defines source-path replacement event.
src/Event/PreQueueRowEvent.php Defines row modification, skipping, and fan-out event.
src/DataSource/Interpreter/AbstractInterpreter.php Dispatches events during interpretation.
src/DependencyInjection/CompilerPass/InterpreterConfigurationFactoryPass.php Injects dispatchers into supported interpreters.
src/Preview/PreviewEventApplier.php Applies events to Studio previews.
src/Hydrator/PreviewHydrator.php Adds event-aware column previews.
src/Service/Studio/PreviewDataService.php Adds event-aware data previews.
src/Service/Studio/TransformationService.php Adds event-aware transformation previews.
src/Resources/config/services.yml Registers the preview event service.
doc/06_Extending/02_Events.md Documents the new extension points.
tests/unit/PreQueueRowEventTest.php Tests row-event state and operations.
tests/unit/InterpreterRowEventTest.php Tests interpreter integration and wiring.
tests/unit/PreviewEventApplierTest.php Tests preview behavior.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Preview/PreviewEventApplier.php
Comment thread src/Preview/PreviewEventApplier.php Outdated
Comment thread src/Preview/PreviewEventApplier.php
Comment thread src/Event/PreInterpretFileEvent.php
Comment thread src/DataSource/Interpreter/AbstractInterpreter.php
Comment thread tests/unit/InterpreterRowEventTest.php Outdated
Comment thread src/Event/PreQueueRowEvent.php
Comment thread doc/06_Extending/02_Events.md Outdated
Comment thread src/Preview/PreviewEventApplier.php
- Add declare(strict_types=1) to both new event classes.
- PreviewEventApplier: skip dispatch for empty preview records, display the
  first fan-out row exactly as queued (no value merging from later rows),
  and drop headers for columns no resulting row contains.
- Document that the preview dispatches only the displayed record (stateful
  listeners should branch on isPreview()) and that interpreters not
  extending AbstractInterpreter must dispatch the events themselves.
- Replace the reflection-based dispatcher-wiring test with a container-level
  compiler-pass test (fixes Sonar php:S3011, removes the broad Throwable catch).
- Add end-to-end regression tests for skipRow() cleanup interaction using a
  stub load strategy: kept identifier survives cleanup, dropped one does not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alexbaat
alexbaat marked this pull request as ready for review August 18, 2026 17:27
@pimcore-deployments
pimcore-deployments marked this pull request as draft August 18, 2026 17:28
Extract label building out of applyToPreviewData (cognitive complexity),
comment the intentionally empty stub methods, and drop the unused closure
parameter in the empty-record preview test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@alexbaat
alexbaat marked this pull request as ready for review August 18, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Data Importer]: Interpretation-stage events (PreInterpretFileEvent, PreQueueRowEvent) to modify/skip/fan-out rows without custom interpreters

3 participants