Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Integration Tests
on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
phpunit:
runs-on: ubuntu-latest
env:
APP_URL: http://localhost:8000
DATABASE_URL: mysql://root@localhost/shopware
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'

- name: Install dependencies
run: |
composer install --no-interaction --prefer-dist --optimize-autoloader

- name: Start MySQL Server
run: |
sudo mv /var/lib/mysql /var/lib/mysql-old
sudo mkdir /var/lib/mysql
sudo mount -t tmpfs tmpfs /var/lib/mysql -o size=1G
sudo -u mysql mysqld --datadir=/var/lib/mysql --default-time-zone=SYSTEM --initialize-insecure
sudo systemctl start mysql

- name: Bootstrap Shopware
run: php vendor/shopware/core/TestBootstrap.php

- name: Run PHPUnit tests
run: vendor/bin/phpunit
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/vendor
/composer.lock
/var
/config
/install.lock
/.phpunit.cache
169 changes: 168 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,179 @@ class CustomFieldFixture implements FixtureInterface
}
```

## 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
<?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

```php
#[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

```php
#[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

```php
#[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

1. **Use meaningful names**: Name your fixtures clearly to indicate what data they create
2. **Organize with groups**: Use groups to categorize fixtures (e.g., 'test-data', 'demo-data', 'performance-test', 'theme-config')
2. **Organize with groups**: Use groups to categorize fixtures (e.g., 'test-data', 'demo-data', 'performance-test', 'theme-config', 'customers')
3. **Declare dependencies explicitly**: Always declare dependencies to ensure correct execution order
4. **Keep fixtures focused**: Each fixture should have a single responsibility
5. **Make fixtures idempotent**: Fixtures should be able to run multiple times without errors
6. **Use dependency injection**: Inject the services you need rather than accessing the container directly
7. **Handle theme errors gracefully**: Use try-catch blocks when configuring optional themes
8. **Use email as unique identifier**: Customer fixtures use email as the primary identifier for updates vs. creation
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
},
"require": {
"php": "^8.2",
"shopware/administration": "^6.6",
"shopware/core": "^6.6",
"shopware/storefront": "^6.6"
"shopware/administration": "^6.6.10",
"shopware/core": "^6.6.10",
"shopware/storefront": "^6.6.10"
},
"extra": {
"shopware-bundle-name": "FixtureBundle"
Expand Down
24 changes: 24 additions & 0 deletions config/bundles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

use Composer\InstalledVersions;
use Shopware\FixtureBundle\FixtureBundle;
use Shopware\Storefront\Storefront;

$bundles = [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Shopware\Core\Profiling\Profiling::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
Shopware\Core\Framework\Framework::class => ['all' => true],
Shopware\Core\System\System::class => ['all' => true],
Shopware\Core\Content\Content::class => ['all' => true],
Shopware\Core\Checkout\Checkout::class => ['all' => true],
Shopware\Core\DevOps\DevOps::class => ['all' => true],
Shopware\Core\Maintenance\Maintenance::class => ['all' => true],
Storefront::class => ['all' => true],
Shopware\Administration\Administration::class => ['all' => true],
FixtureBundle::class => ['all' => true],
];

return $bundles;