Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cartesian Product Laravel Package

bentools/cartesian-product

Generate the cartesian product (all combinations) from a multidimensional array with a low-memory iterator. Supports dynamic values via closures that can inspect the partial combination. Iterate results or dump them to an array when needed.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require bentools/cartesian-product
    

    Requires PHP 8.2+ (check your Laravel project’s php-version in phpunit.xml or .php-version).

  2. First Use Case: Generate all possible combinations of product attributes for a dynamic catalog:

    use function BenTools\CartesianProduct\combinations;
    
    $productAttributes = [
        'color' => ['red', 'blue', 'green'],
        'size'  => ['S', 'M', 'L'],
        'material' => ['cotton', 'polyester'],
    ];
    
    foreach (combinations($productAttributes) as $variant) {
        // Process each unique product variant (e.g., save to DB, generate SKU)
        \Log::info('Variant: ' . json_encode($variant));
    }
    
  3. Key Entry Points:

    • combinations($array): Core function (returns an iterable).
    • ->asArray(): Convert to array (use cautiously for large datasets).
    • ->count(): Get total combinations without generation.
    • ->filter(): Exclude invalid combinations early.
    • ->each(): Transform combinations (e.g., into Eloquent models).

Implementation Patterns

Workflows in Laravel

1. Dynamic Configuration Generation

Use Case: Generate all valid API response formats or feature flag permutations.

$config = [
    'auth' => ['jwt', 'session'],
    'rate_limit' => [100, 500, null], // null = unlimited
    'cache' => ['redis', 'memcached'],
];

foreach (combinations($config)->filter(fn($c) => $c['rate_limit'] !== null) as $configSet) {
    // Store or validate each config permutation
    Config::store($configSet);
}

2. Rule-Based Workflows

Use Case: Conditional logic for order processing (e.g., discounts based on product combinations).

$rules = [
    'discount_tier' => [
        fn($c) => $c['total'] > 1000 ? 'premium' : 'standard',
        fn($c) => $c['total'] > 500 ? 'gold' : null,
    ],
    'shipping' => ['express', 'standard'],
];

foreach (combinations($rules) as $ruleSet) {
    if ($ruleSet['discount_tier'] === 'premium') {
        // Apply premium logic
    }
}

3. Data Transformation Pipelines

Use Case: Convert flat arrays into nested Eloquent models.

$attributes = [
    'title' => ['Book 1', 'Book 2'],
    'author' => ['Author A', 'Author B'],
    'genre' => ['Fiction', 'Non-Fiction'],
];

$books = combinations($attributes)
    ->each(fn($attrs) => Book::create($attrs))
    ->toArray(); // Assuming custom `toArray()` method

4. Integration with Laravel Collections

Use Case: Hybrid operations with Laravel’s Collection methods.

$combinations = combinations($data)->asArray();
$filtered = collect($combinations)->where(fn($c) => $c['price'] > 100);

5. Performance-Optimized Batch Processing

Use Case: Generate test data or reports without memory overload.

$total = combinations($data)->count();
$batchSize = 1000;

for ($i = 0; $i < $total; $i += $batchSize) {
    $batch = array_slice(iter_to_array($combinations), $i, $batchSize);
    processBatch($batch);
}

// Helper: Convert iterable to array (use sparingly)
function iter_to_array(iterable $iterable): array {
    return iterator_to_array($iterable);
}

Integration Tips

  1. Service Container Binding: Bind the function to Laravel’s container for dependency injection:

    $app->bind('combinations', fn() => fn($data) => \BenTools\CartesianProduct\combinations($data));
    
  2. Caching Combinations: Cache expensive combinations (e.g., product variants) using Laravel’s cache:

    $cacheKey = 'product_variants_' . md5(json_encode($attributes));
    $variants = cache()->remember($cacheKey, now()->addHours(1), fn() =>
        combinations($attributes)->asArray()
    );
    
  3. Queue Jobs for Large Datasets: Offload combination generation to background jobs:

    GenerateVariantsJob::dispatch($attributes)->onQueue('combinatorial');
    
  4. Database Seeding: Use for seeding multi-dimensional test data:

    public function run()
    {
        $combinations = combinations($this->data)->asArray();
        DB::table('test_data')->insert($combinations);
    }
    
  5. API Response Generation: Dynamically generate API response structures:

    return response()->json(
        combinations($this->responseTemplates)->asArray()
    );
    

Gotchas and Tips

Pitfalls

  1. Memory Explosion with asArray():

    • Issue: Calling ->asArray() loads all combinations into memory at once.
    • Fix: Use iterative processing (foreach) or chunking for large datasets.
    • Example:
      // Bad: Memory-intensive
      $allCombinations = combinations($data)->asArray();
      
      // Good: Memory-efficient
      foreach (combinations($data) as $combo) {
          // Process one at a time
      }
      
  2. Closure Evaluation Order:

    • Issue: Closures in the input array are evaluated per combination, not once.
    • Fix: Cache dynamic values if expensive:
      $data = [
          'dynamic_value' => function() use (&$cache) {
              return $cache ?? ($cache = expensiveCalculation());
          },
      ];
      
  3. Non-Countable Iterables:

    • Issue: Input arrays with non-countable iterables (e.g., custom generators) will throw \InvalidArgumentException.
    • Fix: Ensure all values implement \Countable or provide a fallback:
      $data = [
          'key' => new class implements \Countable {
              public function count(): int { return 2; }
              public function current() { /* ... */ }
              // ... other Iterator methods
          },
      ];
      
  4. Filtered Count Inaccuracy:

    • Issue: count() on a filtered iterator may return incorrect results (fixed in v2.0.1).
    • Fix: Use iterator_count() for filtered iterators:
      $filtered = combinations($data)->filter(fn($c) => $c['value'] > 10);
      $count = iterator_count($filtered);
      
  5. PHP 8.2+ Features:

    • Issue: Uses modern PHP features (e.g., typed properties, first-class callables).
    • Fix: Ensure your Laravel project targets PHP 8.2+ (check composer.json and server config).

Debugging Tips

  1. Log Combinations for Inspection:

    combinations($data)->each(fn($c) => \Log::debug('Combination:', $c));
    
  2. Validate Input Structure:

    foreach ($data as $key => $values) {
        if (!is_iterable($values)) {
            throw new \InvalidArgumentException("Key '$key' must be iterable.");
        }
    }
    
  3. Profile Memory Usage:

    $start = memory_get_usage();
    foreach (combinations($data) as $combo) { /* ... */ }
    $peak = memory_get_peak_usage();
    \Log::info("Memory usage: " . ($peak - $start) / 1024 / 1024 . "MB");
    

Extension Points

  1. Custom Iterators: Extend the package by creating a decorator:

    class CachedCombinations implements \IteratorAggregate {
        public function __construct(private iterable $combinations) {}
    
        public function getIterator(): \Traversable {
            $cache = [];
            foreach ($this->combinations as $combo) {
                $cache[] = $combo;
            }
            return new \ArrayIterator($cache);
        }
    }
    
  2. Laravel Service Provider: Add helper methods to the Laravel app:

    // app/Providers/AppServiceProvider.php
    public function boot() {
        app()->singleton('combinations', fn() => fn($data) =>
            \BenTools\CartesianProduct\combinations($data)
        );
    }
    
  3. Dynamic Value Generation: Use closures to generate values based on prior selections:

    $data = [
        '
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor