Shopware 6.7 introduces significant enhancements to its bundle system, providing developers with more powerful tools for creating complex product combinations and promotions. Understanding how to effectively utilize this system is crucial for building sophisticated e-commerce solutions that can handle advanced product configurations.

Understanding the Bundle System Architecture

The Shopware 6.7 bundle system is built on top of the existing product management framework but extends it with specialized entities and relationships. At its core, bundles are collections of products that can be purchased together as a single unit with specific pricing rules and conditions.

The main components include:

  • Bundle Entity: Represents the bundle definition
  • BundleProductRelation: Links products to bundles
  • BundlePriceRule: Defines pricing logic for bundles
  • BundleConfiguration: Manages dynamic bundle settings

Setting Up Bundle Entities

Creating a new bundle entity requires extending the existing bundle structure. The typical approach involves defining your bundle in the config/packages directory:

# config/packages/shopware_bundle.yaml
shopware:
    bundle:
        enabled: true
        default_pricing_strategy: 'fixed'
        validation_rules:
            - 'min_quantity'
            - 'max_quantity'
            - 'date_range'

The bundle entity definition follows the standard Shopware 6.7 entity structure:

<?php

declare(strict_types=1);

namespace Shopware\Core\Content\Bundle;

use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait;

class BundleEntity extends Entity
{
    use EntityIdTrait;

    protected string $name;
    
    protected ?string $description;
    
    protected bool $active;
    
    protected array $products;
    
    protected array $pricingRules;
    
    protected \DateTimeInterface $createdAt;
    
    protected ?\DateTimeInterface $updatedAt;
}

Product Association and Relations

The bundle system handles product associations through the bundle_product_relation table. This relationship allows you to define which products belong to a specific bundle and their respective quantities:

CREATE TABLE `bundle_product_relation` (
    `id` BINARY(16) NOT NULL,
    `bundle_id` BINARY(16) NOT NULL,
    `product_id` BINARY(16) NOT NULL,
    `quantity` INT NOT NULL DEFAULT 1,
    `position` INT NOT NULL DEFAULT 0,
    `created_at` DATETIME(3) NOT NULL,
    `updated_at` DATETIME(3) DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `idx_bundle_product` (`bundle_id`, `product_id`),
    CONSTRAINT `fk.bundle_product_relation.bundle_id` 
        FOREIGN KEY (`bundle_id`) REFERENCES `bundle` (`id`) ON DELETE CASCADE,
    CONSTRAINT `fk.bundle_product_relation.product_id` 
        FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Pricing Strategy Implementation

Shopware 6.7 introduces flexible pricing strategies that can be applied to bundles. The system supports multiple pricing models including fixed price, percentage discount, and dynamic calculation based on product values.

<?php

declare(strict_types=1);

namespace Shopware\Core\Content\Bundle\Pricing;

interface BundlePricingStrategyInterface
{
    public function calculatePrice(
        array $products,
        array $bundleConfiguration,
        float $basePrice
    ): float;

    public function getSupportedTypes(): array;
}

class FixedPriceStrategy implements BundlePricingStrategyInterface
{
    public function calculatePrice(
        array $products,
        array $bundleConfiguration,
        float $basePrice
    ): float {
        return $bundleConfiguration['fixed_price'] ?? $basePrice;
    }

    public function getSupportedTypes(): array
    {
        return ['fixed'];
    }
}

class DiscountPercentageStrategy implements BundlePricingStrategyInterface
{
    public function calculatePrice(
        array $products,
        array $bundleConfiguration,
        float $basePrice
    ): float {
        $discount = $bundleConfiguration['discount_percentage'] ?? 0;
        return $basePrice * (1 - $discount / 100);
    }

    public function getSupportedTypes(): array
    {
        return ['percentage_discount'];
    }
}

Advanced Configuration Options

The bundle system in Shopware 6.7 supports advanced configuration options that allow for sophisticated business logic:

<?php

declare(strict_types=1);

namespace Shopware\Core\Content\Bundle\Configuration;

class BundleConfiguration
{
    private array $conditions = [];
    
    private array $constraints = [];
    
    private array $dynamicPricing = [];
    
    private array $availabilityRules = [];
    
    public function addCondition(string $type, array $config): self
    {
        $this->conditions[] = [
            'type' => $type,
            'config' => $config
        ];
        
        return $this;
    }
    
    public function addConstraint(string $type, array $config): self
    {
        $this->constraints[] = [
            'type' => $type,
            'config' => $config
        ];
        
        return $this;
    }
    
    public function setDynamicPricing(array $pricingRules): self
    {
        $this->dynamicPricing = $pricingRules;
        return $this;
    }
    
    public function getConditions(): array
    {
        return $this->conditions;
    }
    
    public function getConstraints(): array
    {
        return $this->constraints;
    }
    
    public function getDynamicPricing(): array
    {
        return $this->dynamicPricing;
    }
}

Integration with Product Streams

Shopware 6.7 enhances bundle functionality by integrating with product streams, allowing you to create dynamic bundles based on product attributes:

<?php

declare(strict_types=1);

namespace Shopware\Core\Content\Bundle\Stream;

class BundleProductStreamProcessor
{
    public function processStream(
        string $streamId,
        array $bundleConfiguration
    ): array {
        $productStream = $this->productStreamRepository->find($streamId);
        
        $products = [];
        foreach ($productStream->getProducts() as $product) {
            if ($this->matchesBundleCriteria($product, $bundleConfiguration)) {
                $products[] = $product;
            }
        }
        
        return $products;
    }
    
    private function matchesBundleCriteria(
        ProductEntity $product,
        array $configuration
    ): bool {
        foreach ($configuration['criteria'] ?? [] as $criterion) {
            if (!$this->evaluateCriterion($product, $criterion)) {
                return false;
            }
        }
        
        return true;
    }
}

Performance Optimization Techniques

When working with complex bundles, performance becomes critical. The bundle system in Shopware 6.7 includes several optimization features:

<?php

declare(strict_types=1);

namespace Shopware\Core\Content\Bundle\Cache;

class BundleCacheManager
{
    private array $cache = [];
    
    private int $ttl = 3600;
    
    public function getBundle(string $bundleId): ?array
    {
        if (isset($this->cache[$bundleId]) && 
            $this->cache[$bundleId]['expires'] > time()) {
            return $this->cache[$bundleId]['data'];
        }
        
        $bundle = $this->loadBundleFromDatabase($bundleId);
        
        $this->cache[$bundleId] = [
            'data' => $bundle,
            'expires' => time() + $this->ttl
        ];
        
        return $bundle;
    }
    
    public function invalidateBundle(string $bundleId): void
    {
        unset($this->cache[$bundleId]);
    }
}

API Integration and Custom Endpoints

The bundle system provides comprehensive API support for external integrations:

<?php

declare(strict_types=1);

namespace Shopware\Core\Content\Bundle\Api;

use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class BundleController
{
    #[Route('/api/v{version}/bundle', methods: ['GET'])]
    public function listBundles(Request $request): JsonResponse
    {
        $criteria = new Criteria();
        $criteria->addAssociation('products');
        $criteria->addAssociation('pricingRules');
        
        $bundles = $this->bundleRepository->search($criteria);
        
        return new JsonResponse([
            'data' => $bundles->getElements(),
            'total' => $bundles->getTotal()
        ]);
    }
    
    #[Route('/api/v{version}/bundle/{id}', methods: ['POST'])]
    public function updateBundle(
        string $id,
        Request $request
    ): JsonResponse {
        $data = json_decode($request->getContent(), true);
        
        $this->bundleRepository->update([[
            'id' => $id,
            'name' => $data['name'],
            'active' => $data['active'],
            'products' => $data['products']
        ]], Context::createDefaultContext());
        
        return new JsonResponse(['success' => true]);
    }
}

Best Practices and Considerations

When implementing bundles in Shopware 6.7, consider these best practices:

  1. Indexing: Ensure proper database indexing on frequently queried bundle fields
  2. Caching: Implement caching strategies for complex bundle calculations
  3. Validation: Include comprehensive validation for bundle configurations
  4. Performance: Monitor performance impact of large bundle structures
  5. Testing: Create thorough test cases for different bundle scenarios

The enhanced bundle system in Shopware 6.7 provides developers with robust tools to create sophisticated product combinations while maintaining the flexibility needed for diverse e-commerce requirements. By understanding and properly implementing these concepts, you can build powerful bundle functionality that enhances your store's capabilities.