shopware / fixture-bundle
Fixture Bundle for Shopware 6
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 0
Open Issues: 0
Type:shopware-bundle
Requires
- php: ^8.2
- shopware/administration: ^6.6.10
- shopware/core: ^6.6.10
- shopware/storefront: ^6.6.10
Requires (Dev)
- phpunit/phpunit: ^10.5
README
The FixtureBundle provides a flexible and organized way to load test data into your Shopware 6 application. It supports dependency management, priority-based execution, and group filtering.
Installation
composer require shopware/fixture-bundle:*
Creating Fixtures
Basic Fixture
Create a class that implements FixtureInterface
and add the #[Fixture]
attribute:
<?php declare(strict_types=1); namespace App\Fixture; use Shopware\FixtureBundle\FixtureInterface; use Shopware\FixtureBundle\Attribute\Fixture; #[Fixture] class BasicFixture implements FixtureInterface { public function load(): void { // Your fixture logic here echo "Loading basic fixture...\n"; } }
Fixture with Priority
Higher priority fixtures are executed first:
#[Fixture(priority: 100)] class HighPriorityFixture implements FixtureInterface { public function load(): void { // This runs before fixtures with lower priority } }
Fixture with Dependencies
Specify other fixtures that must be loaded before this one:
#[Fixture( priority: 50, dependsOn: [CategoryFixture::class] )] class ProductFixture implements FixtureInterface { public function load(): void { // CategoryFixture will always run before this } }
Fixture with Groups
Organize fixtures into groups for selective loading:
#[Fixture( groups: ['test-data', 'products'] )] class ProductTestDataFixture implements FixtureInterface { public function load(): void { // This fixture belongs to both 'test-data' and 'products' groups } }
Complete Example
<?php declare(strict_types=1); namespace App\Fixture; use Doctrine\DBAL\Connection; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; use Shopware\Core\Framework\Uuid\Uuid; use Shopware\FixtureBundle\FixtureInterface; use Shopware\FixtureBundle\Attribute\Fixture; #[Fixture( priority: 100, groups: ['catalog', 'test-data'] )] class CategoryFixture implements FixtureInterface { public function __construct( private readonly EntityRepository $categoryRepository, private readonly Connection $connection ) { } public function load(): void { $categories = [ [ 'id' => Uuid::randomHex(), 'name' => 'Electronics', 'active' => true, ], [ 'id' => Uuid::randomHex(), 'name' => 'Clothing', 'active' => true, ], ]; foreach ($categories as $category) { $this->categoryRepository->create([$category], Context::createDefaultContext()); } } }
Commands
Loading Fixtures
Load all fixtures:
bin/console fixture:load
Load only fixtures from a specific group:
bin/console fixture:load --group=test-data
Listing Fixtures
View all available fixtures and their execution order:
bin/console fixture:list
List fixtures from a specific group:
bin/console fixture:list --group=test-data
Example output:
Available Fixtures
==================
------- -------------------- ---------- ----------------- ------------------
Order Class Priority Groups Depends On
------- -------------------- ---------- ----------------- ------------------
1 CategoryFixture 100 catalog, test- -
data
2 ManufacturerFixture 90 catalog -
3 ProductFixture 50 catalog, test- CategoryFixture,
data ManufacturerFixture
4 CustomerFixture 0 customers -
------- -------------------- ---------- ----------------- ------------------
[OK] Found 4 fixture(s).
Fixture Attributes
The #[Fixture]
attribute accepts the following parameters:
- priority (int, default: 0): Higher values execute first
- dependsOn (array, default: []): Array of fixture class names that must run before this fixture
- groups (array, default: ['default']): Array of group names this fixture belongs to
Execution Order
Fixtures are executed in an order determined by:
- Dependencies: Fixtures with dependencies always run after their dependencies
- Priority: Among fixtures without dependency relationships, higher priority runs first
- Circular dependency detection: The system will throw an exception if circular dependencies are detected
Service Registration
Fixtures are automatically discovered and registered if they:
- Implement the
FixtureInterface
- Have the
#[Fixture]
attribute - Are registered as services (auto-configuration is enabled by default)
Theme Fixtures
The FixtureBundle provides a convenient way to configure theme settings through fixtures using the ThemeFixtureLoader
and ThemeFixtureDefinition
classes.
Basic Theme Fixture
<?php declare(strict_types=1); namespace App\Fixture; use Shopware\FixtureBundle\Attribute\Fixture; use Shopware\FixtureBundle\FixtureInterface; use Shopware\FixtureBundle\Helper\Theme\ThemeFixtureDefinition; use Shopware\FixtureBundle\Helper\Theme\ThemeFixtureLoader; #[Fixture(groups: ['theme-config'])] class ThemeFixture implements FixtureInterface { public function __construct( private readonly ThemeFixtureLoader $themeFixtureLoader ) { } public function load(): void { $this->themeFixtureLoader->apply( (new ThemeFixtureDefinition('Shopware default theme')) ->config('sw-color-brand-primary', '#ff6900') ->config('sw-border-radius-default', '8px') ->config('sw-font-family-base', '"Inter", sans-serif') ->config('sw-background-color', '#f8f9fa') ); } }
Multiple Theme Configuration
#[Fixture(groups: ['theme-config', 'branding'])] class BrandingThemeFixture implements FixtureInterface { public function __construct( private readonly ThemeFixtureLoader $themeFixtureLoader ) { } public function load(): void { // Configure main storefront theme $this->themeFixtureLoader->apply( (new ThemeFixtureDefinition('Shopware default theme')) ->config('sw-color-brand-primary', '#007bff') ->config('sw-color-brand-secondary', '#6c757d') ); // Configure custom theme if available try { $this->themeFixtureLoader->apply( (new ThemeFixtureDefinition('Custom Theme')) ->config('custom-header-color', '#ffffff') ->config('custom-footer-background', '#333333') ); } catch (FixtureException $e) { // Custom theme not available, skip } } }
Setting Logo
#[Fixture(groups: ['theme-config', 'branding'])] class BrandingThemeFixture implements FixtureInterface { public function __construct( private readonly ThemeFixtureLoader $themeFixtureLoader ) { } public function load(): void { // Will be uploaded just once and reused based on file content $logo = $this->mediaHelper->upload(__DIR__ . '/shop.png', $this->mediaHelper->getDefaultFolder(ThemeDefinition::ENTITY_NAME)->getId()); // Configure main storefront theme $this->themeFixtureLoader->apply( (new ThemeFixtureDefinition('Shopware default theme')) ->config('sw-color-brand-primary', '#007bff') ->config('sw-color-brand-secondary', '#6c757d') ->config('sw-logo-desktop', $logo) ->config('sw-logo-tablet', $logo) ->config('sw-logo-mobile', $logo) ); } }
Theme Fixture Features
- Fluent Configuration: Chain multiple
->config()
calls for readability - Automatic Theme Discovery: Finds themes by name automatically
- Change Detection: Only updates and recompiles when configuration actually changes
- Error Handling: Throws
FixtureException::themeNotFound()
if theme doesn't exist - Automatic Recompilation: Theme is automatically recompiled after configuration changes
Available Configuration Fields
Common theme configuration fields include:
sw-color-brand-primary
- Primary brand colorsw-color-brand-secondary
- Secondary brand colorsw-border-radius-default
- Default border radiussw-font-family-base
- Base font familysw-background-color
- Background colorsw-logo-desktop
- Desktop logosw-logo-mobile
- Mobile logosw-logo-tablet
- Tablet logosw-logo-desktop-height
- Desktop logo heightsw-logo-mobile-height
- Mobile logo height
Note: Available fields depend on your theme's configuration schema defined in theme.json
Custom Field Fixtures
The FixtureBundle provides helper classes to easily create and manage custom fields through fixtures using CustomFieldSetFixtureLoader
and related definition classes.
Basic Custom Field Fixture
<?php declare(strict_types=1); namespace Acme\Fixture; use Shopware\Core\System\CustomField\CustomFieldTypes; use Shopware\FixtureBundle\Attribute\Fixture; use Shopware\FixtureBundle\FixtureInterface; use Shopware\FixtureBundle\Helper\CustomField\CustomFieldFixtureDefinition; use Shopware\FixtureBundle\Helper\CustomField\CustomFieldSetFixtureDefinition; use Shopware\FixtureBundle\Helper\CustomField\CustomFieldSetFixtureLoader; #[Fixture] class CustomFieldFixture implements FixtureInterface { public function __construct( private readonly CustomFieldSetFixtureLoader $customFieldSetFixtureLoader ) { } public function load(): void { $this->customFieldSetFixtureLoader->apply( (new CustomFieldSetFixtureDefinition('Product Specifications', 'product_specs')) ->relation('product') ->field( (new CustomFieldFixtureDefinition('weight', CustomFieldTypes::FLOAT)) ->label('en-GB', 'Weight (kg)') ->label('de-DE', 'Gewicht (kg)') ->placeholder('en-GB', 'Enter product weight') ->helpText('en-GB', 'Product weight in kilograms') ->position(10) ) ->field( (new CustomFieldFixtureDefinition('dimensions', CustomFieldTypes::TEXT)) ->label('en-GB', 'Dimensions') ->placeholder('en-GB', 'L x W x H') ->position(20) ) ->field( (new CustomFieldFixtureDefinition('warranty_period', CustomFieldTypes::INT)) ->label('en-GB', 'Warranty Period (months)') ->config(['min' => 0, 'max' => 120]) ->position(30) ) ); } }
Customer Fixtures
The FixtureBundle provides comprehensive customer management through fixtures using CustomerFixtureLoader
and CustomerFixtureDefinition
classes for creating test customers with addresses, custom fields, and relationships.
Basic Customer Fixture
<?php declare(strict_types=1); namespace Acme\Fixture; use Shopware\FixtureBundle\Attribute\Fixture; use Shopware\FixtureBundle\FixtureInterface; use Shopware\FixtureBundle\Helper\Customer\CustomerFixtureDefinition; use Shopware\FixtureBundle\Helper\Customer\CustomerFixtureLoader; #[Fixture] class CustomerFixture implements FixtureInterface { public function __construct( private readonly CustomerFixtureLoader $customerFixtureLoader ) { } public function load(): void { $this->customerFixtureLoader->apply( (new CustomerFixtureDefinition('john.doe@example.com')) ->firstName('John') ->lastName('Doe') ->salutation('mr') ->password('password123') ->company('ACME Corporation') ->department('IT Department') ); } }
Customer with Complete Information
#[Fixture(groups: ['customers', 'test-data'])] class DetailedCustomerFixture implements FixtureInterface { public function __construct( private readonly CustomerFixtureLoader $customerFixtureLoader ) { } public function load(): void { $this->customerFixtureLoader->apply( (new CustomerFixtureDefinition('jane.smith@example.com')) ->firstName('Jane') ->lastName('Smith') ->salutation('mrs') ->title('Dr.') ->birthday('1990-05-15') ->company('Tech Solutions Ltd') ->department('Marketing') ->vatId('DE123456789') ->password('secure123') ->customerNumber('CUST-001') ->affiliateCode('PARTNER-123') ->campaignCode('SUMMER2024') ->active(true) ->guest(false) ->customFields([ 'vip_level' => 'gold', 'newsletter_subscription' => true, 'preferred_contact' => 'email' ]) ); } }
Customer with Addresses
#[Fixture(groups: ['customers', 'addresses'])] class CustomerWithAddressesFixture implements FixtureInterface { public function __construct( private readonly CustomerFixtureLoader $customerFixtureLoader ) { } public function load(): void { $this->customerFixtureLoader->apply( (new CustomerFixtureDefinition('customer@example.com')) ->firstName('Max') ->lastName('Mustermann') ->salutation('mr') ->password('password') ->defaultBillingAddress([ 'firstName' => 'Max', 'lastName' => 'Mustermann', 'street' => 'Musterstraße 123', 'zipcode' => '12345', 'city' => 'Musterstadt', 'country' => 'DEU', 'company' => 'Musterfirma GmbH', 'phoneNumber' => '+49 123 456789', 'salutation' => 'mr' ]) ->defaultShippingAddress([ 'firstName' => 'Max', 'lastName' => 'Mustermann', 'street' => 'Lieferadresse 456', 'zipcode' => '67890', 'city' => 'Lieferstadt', 'country' => 'DEU', 'additionalAddressLine1' => 'Building B', 'additionalAddressLine2' => '3rd Floor' ]) ->addAddress('work', [ 'firstName' => 'Max', 'lastName' => 'Mustermann', 'street' => 'Office Street 789', 'zipcode' => '11111', 'city' => 'Business City', 'country' => 'DEU', 'company' => 'Work Corporation' ]) ); } }
Guest Customer Fixture
#[Fixture(groups: ['customers', 'guest-orders'])] class GuestCustomerFixture implements FixtureInterface { public function __construct( private readonly CustomerFixtureLoader $customerFixtureLoader ) { } public function load(): void { $this->customerFixtureLoader->apply( (new CustomerFixtureDefinition('guest@example.com')) ->firstName('Guest') ->lastName('User') ->guest(true) ->active(false) ->defaultBillingAddress([ 'firstName' => 'Guest', 'lastName' => 'User', 'street' => 'Guest Street 1', 'zipcode' => '99999', 'city' => 'Guest City', 'country' => 'DEU' ]) ); } }
Best Practices
- Use meaningful names: Name your fixtures clearly to indicate what data they create
- Organize with groups: Use groups to categorize fixtures (e.g., 'test-data', 'demo-data', 'performance-test', 'theme-config', 'customers')
- Declare dependencies explicitly: Always declare dependencies to ensure correct execution order
- Keep fixtures focused: Each fixture should have a single responsibility
- Make fixtures idempotent: Fixtures should be able to run multiple times without errors
- Use dependency injection: Inject the services you need rather than accessing the container directly
- Handle theme errors gracefully: Use try-catch blocks when configuring optional themes
- Use email as unique identifier: Customer fixtures use email as the primary identifier for updates vs. creation