fom / module-setup-fixtures
Repeatable fixture import engine for Magento Open Source, Adobe Commerce, and Mage-OS.
Package info
github.com/FriendsOfMagento/module-setup-fixtures
Type:magento2-module
pkg:composer/fom/module-setup-fixtures
Requires
- php: ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0
- magento/framework: ^103.0.7
- magento/module-store: ^101.1.7
Suggests
- fom/module-setup-fixtures-cms: Import CMS pages and blocks from fixtures.
- fom/module-setup-fixtures-email: Import email templates from fixtures.
This package is auto-updated.
Last update: 2026-08-23 20:05:34 UTC
README
A repeatable, hash-based fixture import engine for Magento 2 and Mage-OS.
SetupFixtures lets you keep entity content (CMS pages, blocks, and - through
adapters - any other Magento entity) in version-controlled fixture files that are
re-evaluated on every bin/magento setup:upgrade. Instead of writing a growing chain of
one-shot data patches (CreateHomePageV1, CreateHomePageV2, …), you edit a JSON/HTML
fixture and the engine applies only what actually changed, while preserving manual
admin edits to fields you did not touch.
This is the core engine. It ships no fixtures and no entity types of its own - entity support is added by small adapter modules:
| Module | Role | Repository |
|---|---|---|
| SetupFixtures (this module) | Generic engine: loading, hashing, change detection, state, CLI | module-setup-fixtures |
| SetupFixturesCms | CMS page & block adapter | module-setup-fixtures-cms |
| SetupFixturesCmsHyvaTailwindJit | Hyvä Tailwind JIT CSS extension for CMS fixtures | module-setup-fixtures-cms-hyva-tailwind-jit |
| SetupFixturesEmail | Database email template adapter | module-setup-fixtures-email |
| SetupFixtures Suite | Metapackage bundling the engine and standard adapters | module-setup-fixtures-suite |
Why fixture-based deployment
- One source of truth. Content lives in code, reviewed in pull requests, deployed with the rest of the release.
- Idempotent. Re-running
setup:upgradeis safe - unchanged fixtures are skipped. - Per-field granularity. Each managed field is hashed independently, so editing one field re-applies only that field.
- Admin-safe. The engine compares the last value it applied against the current fixture - not against the live database - so manual admin edits survive as long as the fixture itself did not change.
- No patch sprawl. No version bumps, no new patch classes per change.
Supported versions
The matrix is current as of 2026-08-23. Magento 2.4.4–2.4.6 are not supported because this package does not target PHP 8.1.
Each Magento row was verified with Adobe's non-cumulative July and August 2026 isolated CE patches applied in sequence. These patches do not change the Composer component versions shown in the table.
| Magento | PHP |
|---|---|
| 2.4.7 | 8.2, 8.3 |
| 2.4.8 | 8.3, 8.4 |
| 2.4.9 | 8.5 |
Composer uses bounded component API families (^103.0.7 and ^101.1.7) so compatible
patch releases resolve automatically while the root Magento metapackage controls the exact
security patch. Review the Adobe system requirements,
release schedule,
and versioning policy
when a Magento release line is added or retired.
Mage-OS
| Mage-OS | PHP | Magento base |
|---|---|---|
| 3.4.0 | 8.3, 8.4, 8.5 | 2.4.9 |
Mage-OS 3.4 replaces magento/framework:103.0.9 and
magento/module-store:101.1.9, so the existing Magento component constraints support
both distributions without duplicate alternatives. Mage-OS supports only its latest
release branch; review its release policy and
system requirements when this
matrix is updated.
Installation
Install via Composer:
composer require fom/module-setup-fixtures bin/magento module:enable Fom_SetupFixtures bin/magento setup:upgrade
In most projects you install an adapter (e.g. fom/module-setup-fixtures-cms)
instead, which pulls this engine in as a dependency.
The importer is implemented as Setup/RecurringData, so it runs on every
setup:upgrade - there is nothing to schedule and no version to bump.
How it works (at a glance)
setup:upgrade
└─ Setup\RecurringData
└─ InstallerPool::getAll() one installer per entity type
└─ Installer::execute() iterate registered fixture files
└─ Loader::load() JSON read + load-step pipeline → Fixture
└─ ChangeDetector::detect() per-field hash vs. stored state
└─ ProcessorRunner::before() optional value mutation
└─ ManagedField::apply() write changed fields onto the model
└─ database transaction
└─ EntityPersister::save() persist, return entity id
└─ ProcessorRunner::after() database side data needing the id
└─ StateWriter::write() unless external effects are configured
└─ ProcessorRunner::afterCommit() optional idempotent external effects
└─ StateWriter::write() after external effects succeed
Each entity type is a thin configuration over the generic
Model\Installer\Installer, wired as a DI virtualType. See
docs/architecture.md for the full flow.
Quick start (consuming the engine)
A consumer module ships fixture files and registers their file IDs. The
Fom_SetupFixturesCmsData
example does exactly this on top of the CMS adapter:
app/code/Acme/Content/
├── fixtures/cms/page/home.json
├── fixtures/cms/page/home.html
└── etc/di.xml
etc/di.xml injects the fixture file ID into the CMS page installer:
<virtualType name="Fom\SetupFixturesCms\Model\Page\Installer\Virtual"> <arguments> <argument name="fixtureFiles" xsi:type="array"> <item name="home" xsi:type="string">Acme_Content::fixtures/cms/page/home.json</item> </argument> </arguments> </virtualType>
Then run bin/magento setup:upgrade. See
module-setup-fixtures-cms
for the full CMS fixture format.
CLI commands
| Command | Purpose |
|---|---|
bin/magento setup:fixtures:generate |
Interactively generate a JSON stub from a registered entity type and its managed fields. |
bin/magento setup:fixtures:validate |
Validate every registered fixture without touching the database. |
bin/magento setup:fixtures:status |
Show, per entity key, which fields are unchanged / changed / missing-state. |
bin/magento setup:fixtures:import |
Import outside of setup:upgrade (supports --dry-run, --entity-type, --entity-key, --force). |
bin/magento setup:fixtures:state-reset |
Delete stored state rows to force a clean re-import. |
Full reference: docs/cli-commands.md.
Extending the engine
The engine is entity-agnostic. To support a new Magento entity you provide an
EntityPersisterInterface, a managed-field provider, a key resolver, and register a
Installer virtualType in the InstallerPool - no changes to this module.
- docs/extending-entity-types.md - add a brand-new entity type.
- docs/managed-fields.md - define and extend managed fields.
- docs/load-steps.md - the fixture loading pipeline (content/CSS sidecars, store scope).
- docs/processors.md - before/after-save hooks.
- docs/state-and-hashing.md - state table, hashing, admin-safe behavior.
Documentation
- Architecture
- Load Steps
- Managed Fields
- Processors
- State and Hashing
- Extending Entity Types
- CLI Commands
Related modules
- SetupFixturesCms - CMS page & block adapter; the canonical reference implementation of an entity adapter.
- SetupFixturesCmsHyvaTailwindJit
- extends the CMS adapter with Hyvä Tailwind JIT fields and per-theme CSS persistence; the canonical reference for extending an existing entity adapter.
- SetupFixturesEmail - database email template adapter.
- SetupFixtures Suite - metapackage that installs the engine and standard adapters.
License
Licensed under the Open Software License 3.0 (OSL-3.0).