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().
To begin using th3n3rd/cartesian-product in Laravel, install the package via Composer:
composer require th3n3rd/cartesian-product
A common Laravel use case is generating product variants for an e-commerce platform. Start with a simple example:
use Nerd\CartesianProduct\CartesianProduct;
// Define product attributes
$attributes = [
'size' => ['S', 'M', 'L'],
'color' => ['red', 'blue', 'green'],
'material' => ['cotton', 'polyester']
];
// Create Cartesian product
$cartesianProduct = CartesianProduct::of($attributes);
// Iterate and create variants (memory-efficient)
foreach ($cartesianProduct as $variant) {
\App\Models\ProductVariant::create([
'size' => $variant[0],
'color' => $variant[1],
'material' => $variant[2],
]);
}
Usage section for basic syntax (CartesianProduct::of() vs. empty()->with()).src/CartesianProduct.php for iterator logic and edge-case handling.Use the fluent API to build products incrementally:
$productBuilder = CartesianProduct::empty();
$productBuilder->with(['size' => ['S', 'M', 'L']]);
$productBuilder->with(['color' => ['red', 'blue']]);
// Process in batches (e.g., per request or queue job)
foreach ($productBuilder as $variant) {
// Process $variant (e.g., create records, generate URLs)
}
Combine with Laravel’s Collection for additional processing:
use Illuminate\Support\Collection;
$variants = collect(CartesianProduct::of([
['size' => ['S', 'M']],
['color' => ['red', 'blue']],
]));
// Group by size
$grouped = $variants->groupBy('size');
Offload memory-intensive operations to Laravel queues:
use Illuminate\Support\Facades\Queue;
$attributes = [
'size' => ['S', 'M', 'L', 'XL'],
'color' => ['red', 'blue', 'green', 'black'],
];
Queue::push(function () use ($attributes) {
$cartesian = CartesianProduct::of($attributes);
foreach ($cartesian as $variant) {
\App\Models\ProductVariant::create($variant);
}
});
Generate dynamic API responses (e.g., for filtering):
$filters = [
'price_range' => ['0-50', '50-100', '100+'],
'category' => ['electronics', 'clothing'],
];
$combinations = CartesianProduct::of($filters)->toArray();
return response()->json(['filters' => $combinations]);
To integrate with Laravel’s DI container, create a wrapper:
// app/Providers/CartesianProductServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Nerd\CartesianProduct\CartesianProduct;
class CartesianProductServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(CartesianProduct::class, function () {
return new CartesianProduct();
});
}
}
Use Cartesian products to generate related models:
// In a Product model
public function variants()
{
$attributes = [
'size' => $this->sizes,
'color' => $this->colors,
];
return $this->hasMany(ProductVariant::class)
->whereIn('size', $attributes['size'])
->whereIn('color', $attributes['color']);
}
// Then use CartesianProduct to validate or generate missing variants
Generate routes for all product combinations:
$routes = [];
foreach (CartesianProduct::of([
['size' => ['S', 'M']],
['color' => ['red', 'blue']],
]) as $params) {
$routes[] = route('products.show', $params);
}
Memory Leaks with toArray()
toArray() on large datasets (e.g., >1,000 combinations) as it materializes all results in memory.foreach or use chunking.Static Factory Conflicts
CartesianProduct::of()) bypass Laravel’s DI container.$cartesian = new \Nerd\CartesianProduct\CartesianProduct();
$cartesian->with([...]);
Empty Array Handling
with() or of() may not behave as expected.$arrays = array_filter($inputArrays, fn($arr) => !empty($arr));
$cartesian = CartesianProduct::of($arrays);
Recursion Depth Limits
Laravel Queue Timeouts
$count = 0;
foreach ($cartesian as $item) $count++;
dd($count); // Should equal product of input array sizes
Custom Iterators
Extend the base CartesianProduct class to add Laravel-specific logic:
class LaravelCartesianProduct extends CartesianProduct
{
public function toCollection()
{
return collect(iterator_to_array($this));
}
}
Caching Layer Cache Cartesian products for repeated use (e.g., product variants):
$cacheKey = 'product_variants_' . md5(serialize($attributes));
$variants = Cache::remember($cacheKey, now()->addHours(1), function () use ($attributes) {
return CartesianProduct::of($attributes)->toArray();
});
Event Dispatching Trigger events during iteration (e.g., for analytics):
foreach ($cartesian as $variant) {
event(new VariantGenerated($variant));
// ...
}
Database Integration Use the iterator to bulk insert variants:
DB::table('product_variants')->insert(
iterator_to_array($cartesian)
);
$chunkSize = 1000;
$iterator = CartesianProduct::of($attributes);
$chunk = [];
foreach ($iterator as $item) {
$chunk[] = $item;
if (count($chunk) === $chunkSize) {
Process::chunk($chunk);
$chunk = [];
}
}
if (!empty($chunk)) {
Process::chunk($chunk);
}
parallel helper for CPU-bound tasks:
parallel([
fn() => $this->processChunk($cartesian, 0, 500),
fn() => $this->processChunk($cartesian, 500, 1000),
]);
How can I help you explore Laravel packages today?