You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Docs: bring CLAUDE.md + README.md up to date with the 1.x engine
CLAUDE.md: rewrite the Architecture section for the new async flow (ProcessFeed ->
GenerateFeedContext -> inline or fan-out via GenerateFeedChunk/FinalizeFeedContext ->
FeedContextFinalizer -> publish gate -> per-context gated promotion + delivery), the
FeedGraph states (ready/processing/completed/failed), the tagged extension-point
registries, field-mapping-and-writer output model, preview/audit diagnostics,
delivery/split/gzip, and LookupTable enrichment. Document the dependency-analysis
require-only gotcha (split Sylius packages + the flysystem constraint split) and that
only English translations ship so far.
README.md: describe the resource-agnostic engine + its capabilities, fix the routing
import to the real files (routes.yaml + routes/admin.yaml), and align the usage/cron
section with setono:feed:process.
Copy file name to clipboardExpand all lines: CLAUDE.md
+95-50Lines changed: 95 additions & 50 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -161,7 +161,7 @@ These are enforced by `.github/workflows/build.yaml` and will fail the build if
161
161
-**PHP 8.1 is the floor**: the package supports PHP `>=8.1`, and CI runs against 8.1/8.2/8.3 with Symfony `~6.4`. Coding-standards run on **8.1** and Rector targets `LevelSetList::UP_TO_PHP_81`, so do **not** use syntax/features newer than 8.1.
162
162
-**`lowest` and `highest` dependencies** are both tested — avoid relying on behavior only present in newer versions of a `^`-constrained dependency.
-**Dependency analysis** (`shipmonk/composer-dependency-analyser`, config in `composer-dependency-analyser.php`) checks that every used package is a direct dependency.
164
+
- **Dependency analysis** (`shipmonk/composer-dependency-analyser`, config in `composer-dependency-analyser.php`) must pass: every symbol used in `src/` maps to a declared `require`, and every `require` is used. **Gotcha:** the job runs `composer config --unset require-dev` and resolves **`require`-only**, so it never sees the `sylius/sylius` monorepo (a require-dev dependency) — it pulls the *split* component packages (`sylius/core`, `sylius/order`, …) instead. Two consequences: (a) `require` must directly declare every Sylius component the code uses (the split packages don't `replace` each other); (b) the split `sylius/core` caps `league/flysystem` at `^2.4`, so `require` keeps `league/flysystem: ^2.4 || ^3.0` and the 3.x floor + `league/flysystem-local` live in **require-dev** (the test app and the full install still resolve flysystem 3.15 + flysystem-local 3.15, matched so `ChecksumProvider` is present). Reproduce the exact job locally with: `cp composer.json /tmp/bak && composer config --unset require-dev && composer require --dev --no-install shipmonk/composer-dependency-analyser && composer update --prefer-lowest --ignore-platform-req=php+ && vendor/bin/composer-dependency-analyser` (then `cp /tmp/bak composer.json && composer update`).
165
165
166
166
### Test Application
167
167
The plugin includes a test Symfony application in `tests/Application/` for development and testing:
@@ -194,74 +194,119 @@ Examples:
194
194
195
195
## Architecture
196
196
197
-
### Feed Processing Flow
198
-
199
-
The pipeline is a fan-out of async messages, and the *lifecycle* is driven by Symfony Workflow transition events — not by the handlers calling each other directly.
200
-
201
-
1.`ProcessFeedsCommand` (`setono:sylius-feed:process`) calls `FeedProcessor::process()`, which dispatches one `ProcessFeed` per enabled feed.
202
-
2.`ProcessFeedHandler` validates the feed type's template, applies the `process` transition, and dispatches one `GenerateFeed` per channel/locale combination.
203
-
3.`GenerateFeedHandler` asks the feed type's `DataProvider` for batches (`getBatches()`) and dispatches one `GenerateBatch` per batch.
204
-
4.`GenerateBatchHandler` resolves the batch's items, runs each through the item context, validates every context, renders the Twig `item` block, writes a **partial file** per channel/locale, then dispatches `BatchGeneratedEvent`.
205
-
5.`FinishGenerationHandler` concatenates the partials into the final feed (wrapping them with the feed start/end rendered from `@SetonoSyliusFeedPlugin/Feed/feed.txt.twig`, split on the `<!-- ITEM_BOUNDARY -->` marker), deletes the partials, and applies the `processed` transition.
206
-
207
-
**Completion detection is counter-based, not "last handler wins".** The total batch count is set on the feed when the `process` transition fires (`StartProcessingSubscriber` → `Feed::setBatches()`). On each `BatchGeneratedEvent`, `IncrementFinishedBatchesSubscriber` (priority 100) increments the counter, then `SendFinishGenerationCommandSubscriber` dispatches `FinishGeneration` only once `FeedRepository::batchesGenerated()` is true. This is what makes the flow safe under out-of-order async batch processing.
197
+
The plugin is a **resource-agnostic transformation engine**: *iterate any Sylius resource → map each
198
+
entity to named output fields → transform/filter → validate → stream to a format → gate → publish/
199
+
deliver*. "Google Shopping product feed" is just the richest `FeedType` plugged into that engine. The
200
+
authoritative design lives in `.notes/sylius-feed-plugin-spec.md` (gitignored).
208
201
209
-
**Workflow-transition subscribers** (`workflow.setono_sylius_feed.feed.transition.*`) handle side effects so handlers stay focused:
210
-
-`process` → `StartProcessingSubscriber` resets and sets the batch count.
211
-
-`processed` → `MoveGeneratedFeedSubscriber` moves the feed from the temporary filesystem to its final (public) location.
212
-
-`errored` → `DeleteGeneratedFilesSubscriber` cleans up generated files.
213
-
214
-
**Validation/violation behavior:** each context is validated with the feed type's validation groups. A violation with severity `error` causes that item to be **skipped** (not written to the feed); other severities are recorded as `Violation`s on the feed but the item is still written. Any thrown error transitions the feed to `error`.
215
-
216
-
### Key Components
202
+
### Feed Processing Flow
217
203
218
-
-**FeedType** (`FeedTypeInterface`): Defines a feed format. Contains data provider, templates, feed context, and item context. Register with tag `setono_sylius_feed.feed_type`.
219
-
-**DataProvider** (`DataProviderInterface`): Provides items to be included in the feed (e.g., products)
220
-
-**FeedContext/ItemContext**: Transform raw data into context for Twig templates
0 commit comments