From db98dcc4fe65afdd0a39d37f85483d65bbc3a621 Mon Sep 17 00:00:00 2001 From: thapacodes4u Date: Sun, 5 Oct 2025 19:04:27 +0545 Subject: [PATCH] feat: optimizing the product seeder --- database/factories/ProductFactory.php | 16 +- database/seeders/ProductSeeder.php | 217 +++++++++++++++++++------- 2 files changed, 165 insertions(+), 68 deletions(-) diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index 6f3010d..f954709 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -3,10 +3,8 @@ namespace Eclipse\Catalogue\Factories; use Eclipse\Catalogue\Models\Product; -use Exception; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\Log; class ProductFactory extends Factory { @@ -47,21 +45,17 @@ public function definition(): array ]; } - public function configure(): static + public function withImages(): static { return $this->afterCreating(function (Product $product) { $imageNumber = rand(1, 15); $imagePath = storage_path("app/public/sample-products/{$imageNumber}.jpg"); if (file_exists($imagePath)) { - try { - $product->addMedia($imagePath) - ->preservingOriginal() - ->withCustomProperties(['is_cover' => true]) - ->toMediaCollection('images'); - } catch (Exception $e) { - Log::warning("Failed to attach image to product {$product->id}: ".$e->getMessage()); - } + $product->addMedia($imagePath) + ->preservingOriginal() + ->withCustomProperties(['is_cover' => true]) + ->toMediaCollection('images'); } }); } diff --git a/database/seeders/ProductSeeder.php b/database/seeders/ProductSeeder.php index 754a8cd..a327ebe 100644 --- a/database/seeders/ProductSeeder.php +++ b/database/seeders/ProductSeeder.php @@ -9,7 +9,7 @@ use Eclipse\Catalogue\Models\ProductType; use Exception; use Illuminate\Database\Seeder; -use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; class ProductSeeder extends Seeder @@ -23,7 +23,7 @@ public function run(): void $productTypes = ProductType::all(); Product::factory() - ->count(100) + ->count(20) ->create([ 'product_type_id' => function () use ($productTypes) { return $productTypes->random()->id; @@ -33,106 +33,188 @@ public function run(): void $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); $tenantModel = config('eclipse-catalogue.tenancy.model'); - $products = Product::query()->latest('id')->take(100)->get(); + $products = Product::query()->latest('id')->take(20)->get(); + $groupProductInserts = []; + $productDataInserts = []; - foreach ($products as $index => $product) { - if ($tenantFK && $tenantModel && class_exists($tenantModel)) { - $tenants = $tenantModel::all(); + if ($tenantFK && $tenantModel && class_exists($tenantModel)) { + $tenants = $tenantModel::all(); + + $categoriesByTenant = Category::query() + ->withoutGlobalScopes() + ->get() + ->groupBy($tenantFK); + + $groupsByTenant = Group::all()->groupBy($tenantFK); + + foreach ($products as $index => $product) { foreach ($tenants as $tenant) { - $categoryId = Category::query() - ->withoutGlobalScopes() - ->where($tenantFK, $tenant->id) - ->inRandomOrder() - ->value('id'); + $categories = $categoriesByTenant->get($tenant->id); + $categoryId = $categories?->random()?->id; - ProductData::factory()->create([ + $productDataInserts[] = [ 'product_id' => $product->id, $tenantFK => $tenant->id, 'is_active' => true, 'has_free_delivery' => false, 'category_id' => $categoryId, - ]); + ]; - // Get groups for this specific tenant - $tenantGroups = Group::where($tenantFK, $tenant->id)->get(); + $tenantGroups = $groupsByTenant->get($tenant->id, collect()); $groupsToAdd = $this->determineGroupsForProduct($index, $tenantGroups); - foreach ($groupsToAdd as $group) { - $group->addProduct($product); + foreach ($groupsToAdd as $groupIndex => $group) { + $groupProductInserts[] = [ + 'group_id' => $group->id, + 'product_id' => $product->id, + 'sort' => $groupIndex + 1, + ]; } } - } else { - $categoryId = Category::query()->inRandomOrder()->value('id'); + } + } else { + $categories = Category::all(); + $groups = Group::all(); - ProductData::factory()->create([ + foreach ($products as $index => $product) { + $productDataInserts[] = [ 'product_id' => $product->id, 'is_active' => true, 'has_free_delivery' => false, - 'category_id' => $categoryId, - ]); + 'category_id' => $categories->random()->id, + ]; - // For non-tenant scenarios, use all groups - $groups = Group::all(); $groupsToAdd = $this->determineGroupsForProduct($index, $groups); - foreach ($groupsToAdd as $group) { - $group->addProduct($product); + foreach ($groupsToAdd as $groupIndex => $group) { + $groupProductInserts[] = [ + 'group_id' => $group->id, + 'product_id' => $product->id, + 'sort' => $groupIndex + 1, + ]; } } } + + if (! empty($productDataInserts)) { + ProductData::insert($productDataInserts); + } + + if (! empty($groupProductInserts)) { + DB::table('pim_group_has_product')->insert($groupProductInserts); + } + + $this->attachImagesToProducts($products); } private function determineGroupsForProduct(int $productIndex, $groups): array { - $groupsToAdd = []; + if ($groups->isEmpty()) { + return []; + } - // Randomly assign 1-3 groups per product $numGroupsToAdd = rand(1, min(3, $groups->count())); - // Get random groups for this product - $randomGroups = $groups->random($numGroupsToAdd); - - foreach ($randomGroups as $group) { - $groupsToAdd[] = $group; - } - - return $groupsToAdd; + return $groups->random($numGroupsToAdd)->all(); } private function ensureSampleImagesExist(): void { Storage::disk('public')->makeDirectory('sample-products'); - $existingImages = Storage::disk('public')->files('sample-products'); - - if (count($existingImages) >= 15) { - $this->command->info('Sample images already exist.'); - + if (count(Storage::disk('public')->files('sample-products')) >= 15) { return; } - $this->command->info('Downloading sample product images...'); - for ($i = 1; $i <= 15; $i++) { - $imagePath = "sample-products/{$i}.jpg"; - - if (Storage::disk('public')->exists($imagePath)) { + if (Storage::disk('public')->exists("sample-products/{$i}.jpg")) { continue; } - try { - $imageUrl = "https://picsum.photos/400/300?random={$i}"; - $response = Http::timeout(10)->get($imageUrl); + $image = $this->generatePlaceholderImage($i); + Storage::disk('public')->put("sample-products/{$i}.jpg", $image); + } + } - if ($response->successful()) { - Storage::disk('public')->put($imagePath, $response->body()); - $this->command->info("Downloaded image {$i}/15"); - } - } catch (Exception $e) { - $this->command->warn("Failed to download image {$i}: ".$e->getMessage()); - } + private function generatePlaceholderImage(int $index): string + { + $image = imagecreatetruecolor(400, 300); + $hue = ($index * 24) % 360; + + $this->drawBackground($image, $hue); + $this->drawShapes($image, $hue); + $this->drawOverlay($image, $hue); + + ob_start(); + imagejpeg($image, null, 85); + $imageData = ob_get_clean(); + imagedestroy($image); + + return $imageData; + } + + private function drawBackground($image, int $hue): void + { + [$r, $g, $b] = $this->hslToRgb($hue / 360, 0.6, 0.5); + $bgColor = imagecolorallocate($image, $r, $g, $b); + imagefill($image, 0, 0, $bgColor); + } + + private function drawShapes($image, int $baseHue): void + { + for ($i = 0; $i < 50; $i++) { + $hue = ($baseHue + rand(-30, 30)) / 360; + [$r, $g, $b] = $this->hslToRgb($hue, rand(40, 80) / 100, rand(30, 70) / 100); + $color = imagecolorallocate($image, $r, $g, $b); + + match (rand(0, 2)) { + 0 => imagefilledellipse($image, rand(0, 400), rand(0, 300), rand(20, 100), rand(20, 100), $color), + 1 => imageline($image, rand(0, 400), rand(0, 300), rand(0, 400), rand(0, 300), $color), + 2 => imagefilledrectangle($image, rand(0, 400), rand(0, 300), rand(0, 400), rand(0, 300), $color), + }; + } + } + + private function drawOverlay($image, int $baseHue): void + { + for ($i = 0; $i < 3; $i++) { + [$r, $g, $b] = $this->hslToRgb($baseHue / 360, 0.1, rand(80, 95) / 100); + $overlayColor = imagecolorallocatealpha($image, $r, $g, $b, rand(90, 110)); + imagefilledellipse($image, rand(-50, 350), rand(-50, 250), rand(200, 400), rand(200, 400), $overlayColor); + } + } + + private function hslToRgb(float $h, float $s, float $l): array + { + if ($s == 0) { + $rgb = $l; + + return [round($rgb * 255), round($rgb * 255), round($rgb * 255)]; } - $this->command->info('Sample images ready!'); + $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s; + $p = 2 * $l - $q; + + return [ + round($this->hueToRgb($p, $q, $h + 1 / 3) * 255), + round($this->hueToRgb($p, $q, $h) * 255), + round($this->hueToRgb($p, $q, $h - 1 / 3) * 255), + ]; + } + + private function hueToRgb(float $p, float $q, float $t): float + { + $t = match (true) { + $t < 0 => $t + 1, + $t > 1 => $t - 1, + default => $t, + }; + + return match (true) { + $t < 1 / 6 => $p + ($q - $p) * 6 * $t, + $t < 1 / 2 => $q, + $t < 2 / 3 => $p + ($q - $p) * (2 / 3 - $t) * 6, + default => $p, + }; } private function ensureProductTypesExist(): void @@ -152,4 +234,25 @@ private function ensureGroupsExist(): void $this->call(GroupSeeder::class); } } + + private function attachImagesToProducts($products): void + { + $productsWithImages = $products->random(10); + + foreach ($productsWithImages as $index => $product) { + $imageNumber = ($index % 15) + 1; + $sourceFileName = "{$imageNumber}.jpg"; + $sourcePath = storage_path("app/public/sample-products/{$sourceFileName}"); + + if (file_exists($sourcePath)) { + try { + $product->addMedia($sourcePath) + ->preservingOriginal() + ->withCustomProperties(['is_cover' => true]) + ->toMediaCollection('images', 'public'); + } catch (Exception $e) { + } + } + } + } }