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

th3n3rd/cartesian-product

Memory-efficient Cartesian Product generator for PHP. Uses iterators to yield one tuple at a time, letting you handle very large combinations without big memory usage. Build products via fluent with() calls or CartesianProduct::of(), iterate or toArray().

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation: Add the package via Composer in your Laravel project:

    composer require th3n3rd/cartesian-product
    

    No additional configuration is required—it’s a standalone package with no Laravel-specific dependencies.

  2. First Use Case: Dynamic Query Builder Clauses: Generate all possible combinations of filter conditions for a complex search API.

    use Nerd\CartesianProduct\CartesianProduct;
    
    // Define filter options (e.g., from a request or config)
    $filters = [
        ['status' => ['active', 'inactive']],
        ['category' => ['electronics', 'clothing']],
        ['price_range' => ['0-50', '50-100']],
    ];
    
    $cartesianProduct = CartesianProduct::of($filters);
    
    // Stream combinations to build dynamic queries
    foreach ($cartesianProduct as $combination) {
        $query = Model::query();
        foreach ($combination as $field => $value) {
            $query->where($field, $value);
        }
        // Process each unique query (e.g., cache results, log, or execute)
    }
    
  3. Where to Look First:

    • README.md: Focus on the CartesianProduct::of() and CartesianProduct::empty()->with() methods for chaining.
    • Iterator Usage: Prioritize lazy evaluation (foreach) over toArray() for memory efficiency.
    • Laravel Integration: Explore how to wrap the iterator in a Laravel service or collection macro for reuse.

Implementation Patterns

Usage Patterns

  1. Lazy Evaluation with Iterators: Use iterators for large datasets to avoid memory spikes. Example: Generating test cases for API validation.

    $testCases = CartesianProduct::of([
        ['user_type' => ['admin', 'guest']],
        ['device' => ['mobile', 'desktop']],
        ['location' => ['us', 'eu']],
    ]);
    
    foreach ($testCases as $case) {
        $response = Http::post('/api/endpoint', $case);
        // Assert or log response
    }
    
  2. Chaining with Laravel Collections: Combine with Laravel’s collect() for fluent operations like filtering or mapping.

    $combinations = collect(CartesianProduct::of([
        ['size' => ['S', 'M', 'L']],
        ['color' => ['red', 'blue']],
    ])->toArray()) // Convert to array for collection
    ->filter(fn ($combo) => $combo['size'] !== 'M') // Skip medium sizes
    ->map(fn ($combo) => [
        'sku' => "{$combo['size']}_{$combo['color']}",
        'price' => 10 + (strlen($combo['size']) * 2),
    ]);
    
  3. Async Processing with Queues: Offload large Cartesian products to queues for background processing.

    // In a Laravel command or controller
    $combinations = CartesianProduct::of([/* large arrays */]);
    
    foreach ($combinations as $combination) {
        ProcessCombinationJob::dispatch($combination);
    }
    
  4. Dynamic Rule Engines: Generate all possible rule permutations for a workflow engine.

    $rules = CartesianProduct::of([
        ['action' => ['notify', 'block']],
        ['trigger' => ['login', 'purchase']],
        ['condition' => ['failed', 'success']],
    ]);
    
    foreach ($rules as $rule) {
        $workflow->addRule($rule);
    }
    

Workflows

  1. API Filter Generation:

    • Input: User-selected filters (e.g., status, category).
    • Process: Generate all valid filter combinations.
    • Output: Dynamic query scopes or cached filter results.
    $filterCombinations = CartesianProduct::of([
        ['status' => request('status', ['active', 'inactive'])],
        ['category' => request('category', ['electronics', 'books'])],
    ]);
    
    // Cache combinations for later use
    Cache::put('filter_combinations', iterator_to_array($filterCombinations), now()->addHour());
    
  2. Recommendation Engines:

    • Input: Product attributes (e.g., color, size, material).
    • Process: Generate "frequently bought together" combinations.
    • Output: Precompute and store in a recommendations table.
    $productCombinations = CartesianProduct::of([
        ['color' => ['red', 'blue']],
        ['size' => ['S', 'M']],
    ]);
    
    foreach ($productCombinations as $combo) {
        Recommendation::create([
            'product_a' => Product::where('color', $combo['color'])->first(),
            'product_b' => Product::where('size', $combo['size'])->first(),
            'weight' => rand(1, 10),
        ]);
    }
    
  3. Data Migration:

    • Input: Legacy data schemas (e.g., nested arrays).
    • Process: Flatten or transform data using Cartesian products.
    • Output: Migrated data in a normalized format.
    $legacyData = [
        ['type' => ['A', 'B']],
        ['value' => [1, 2, 3]],
    ];
    
    $migratedData = [];
    foreach (CartesianProduct::of($legacyData) as $row) {
        $migratedData[] = [
            'legacy_type' => $row['type'],
            'legacy_value' => $row['value'],
            'normalized' => "{$row['type']}_{$row['value']}",
        ];
    }
    

Integration Tips

  1. Laravel Service Container: Bind the CartesianProduct class for dependency injection.

    // In AppServiceProvider@boot()
    $this->app->bind(CartesianProduct::class, function () {
        return new CartesianProduct();
    });
    

    Usage in controllers:

    public function __construct(private CartesianProduct $cartesianProduct) {}
    
  2. Collection Macros: Extend Laravel Collections to support Cartesian products natively.

    // In AppServiceProvider@boot()
    Collect::macro('cartesian', function ($arrays) {
        return $this->pipe(fn ($collection) => CartesianProduct::of($arrays));
    });
    

    Usage:

    $combinations = collect([])->cartesian([
        ['status' => ['active', 'inactive']],
        ['priority' => ['high', 'low']],
    ]);
    
  3. Eloquent Relationships: Dynamically generate relationship combinations for polymorphic queries.

    $relationshipCombinations = CartesianProduct::of([
        ['model' => [User::class, Product::class]],
        ['relation' => ['posts', 'reviews']],
    ]);
    
    foreach ($relationshipCombinations as $combo) {
        $query = $combo['model']::query()->with($combo['relation']);
        // Execute or cache query
    }
    
  4. Testing: Use the package to generate test data or edge cases.

    public function test_combinatorial_logic()
    {
        $testCases = CartesianProduct::of([
            ['input' => [1, 2]],
            ['operation' => ['+', '-']],
        ]);
    
        foreach ($testCases as $case) {
            $result = $case['input'] . $case['operation'] . '1';
            $this->assertTrue(eval("return {$result};"));
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Memory Spikes with toArray():

    • Issue: Calling toArray() on large Cartesian products can exhaust memory.
    • Fix: Always prefer iterators (foreach) for large datasets. If you must use toArray(), ensure the dataset is small (e.g., <10,000 combinations) or process in chunks.
    • Debugging: Monitor memory usage with memory_get_usage():
      $startMemory = memory_get_usage();
      $result = $cartesianProduct->toArray();
      Log::warning("Memory used: " . (memory_get_usage() - $startMemory) . " bytes");
      
  2. Empty Input Handling:

    • Issue: CartesianProduct::of([]) or CartesianProduct::empty() returns an empty iterator, which may not be intuitive.
    • Fix: Validate inputs explicitly:
      if (empty($arrays)) {
          return collect([]); // or throw new InvalidArgumentException("Input arrays cannot be empty.");
      }
      
  3. Iterator State:

    • Issue: Iterators are stateful and cannot be reused after exhaustion.
    • Fix: Recreate the iterator if needed:
      $iterator = CartesianProduct::of([/* arrays */]);
      foreach ($iterator as $item) { /* first pass */ }
      foreach ($iterator as $item) { /* will not yield
      
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi