Deploy / deploy (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
104 lines
3.5 KiB
PHP
104 lines
3.5 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Product;
|
|
use App\Services\ShopifyService;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ShopifyImages extends Command
|
|
{
|
|
protected $signature = 'shopify:images {--force : Bilder auch für Produkte neu laden die schon welche haben}';
|
|
protected $description = 'Lädt Produktbilder von Shopify herunter und speichert sie lokal';
|
|
|
|
public function handle(ShopifyService $shopify): int
|
|
{
|
|
$variants = $shopify->getAllVariants();
|
|
|
|
if (empty($variants)) {
|
|
$this->error('Keine Daten von Shopify erhalten (Details im Log).');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
// Deduplizieren: pro Produkttitel nur einmal
|
|
$shopifyProducts = collect($variants)
|
|
->filter(fn($v) => ! empty($v['image_urls']))
|
|
->keyBy('product_title');
|
|
|
|
$totalInShopify = collect($variants)->pluck('product_title')->unique()->count();
|
|
$this->info("Shopify-Produkte gesamt: {$totalInShopify}");
|
|
$this->info("Davon mit Bild-URLs: {$shopifyProducts->count()}");
|
|
|
|
if ($shopifyProducts->isEmpty()) {
|
|
$this->warn('Kein Shopify-Produkt hat Bild-URLs — Import nicht möglich.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$downloaded = 0;
|
|
$skipped = 0;
|
|
$notFound = 0;
|
|
|
|
foreach ($shopifyProducts as $title => $variant) {
|
|
$product = Product::where('title', $title)->first();
|
|
|
|
if (! $product) {
|
|
$this->warn(" Nicht lokal gefunden: \"{$title}\"");
|
|
$notFound++;
|
|
continue;
|
|
}
|
|
|
|
if (! empty($product->images) && ! $this->option('force')) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
$paths = [];
|
|
foreach ($variant['image_urls'] as $url) {
|
|
try {
|
|
$response = Http::timeout(30)->get($url);
|
|
} catch (\Exception $e) {
|
|
$this->warn(" Verbindungsfehler für {$url}: {$e->getMessage()}");
|
|
continue;
|
|
}
|
|
|
|
if ($response->failed()) {
|
|
$this->warn(" HTTP {$response->status()} für: {$url}");
|
|
continue;
|
|
}
|
|
|
|
$body = $response->body();
|
|
if (empty($body)) {
|
|
$this->warn(" Leere Antwort für: {$url}");
|
|
continue;
|
|
}
|
|
|
|
$ext = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
|
|
$filename = 'product-images/' . Str::uuid() . '.' . $ext;
|
|
Storage::disk('public')->put($filename, $body);
|
|
$paths[] = $filename;
|
|
}
|
|
|
|
if (! empty($paths)) {
|
|
$product->update(['images' => $paths]);
|
|
$this->line(" ✓ {$title} (" . count($paths) . " Bild(er))");
|
|
$downloaded++;
|
|
} else {
|
|
$this->warn(" Keine Bilder gespeichert für: \"{$title}\"");
|
|
}
|
|
}
|
|
|
|
$this->info("✓ {$downloaded} Produkte mit Bildern versorgt");
|
|
if ($skipped) {
|
|
$this->line(" {$skipped} übersprungen (haben bereits Bilder — nutze --force zum Überschreiben)");
|
|
}
|
|
if ($notFound) {
|
|
$this->warn(" {$notFound} Shopify-Produkte lokal nicht gefunden (Titelabweichung?)");
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|