PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, // <— włącz buffer ]); // Otwórz CSV $fh = fopen($outFile, "w"); if (!$fh) die("Nie mogę utworzyć pliku CSV: {$outFile}\n"); // (Opcjonalnie) BOM dla Excela na Windows fwrite($fh, "\xEF\xBB\xBF"); // Nagłówek $header = [ 'id_product', 'id_product_attribute', 'product_name', 'manufacturer', 'default_category', 'active', 'price_tax_excl', 'quantity', 'reference', 'ean13', 'weight', 'comb_reference', 'comb_ean13', 'comb_weight', 'comb_quantity', 'attributes', // "Grupa: Wartość | Grupa2: Wartość2" 'features' // "Cecha: Wartość | Cecha2: Wartość2" ]; fputcsv($fh, $header, $delimiter); // ===== POMOCNICZE FUNKCJE ===== function getProductFeatures(PDO $pdo, $prefix, $idLang, $idProduct): array { // Fallback: weź tłumaczenie w :id_lang, a jeśli go nie ma – w minimalnym (dowolnym) id_lang $sql = " SELECT COALESCE(fl.name, fl_any.name, '') AS feature_name, COALESCE(fvl.value, fvl_any.value, '') AS feature_value FROM {$prefix}feature_product fp /* nazwa cechy w żądanym języku */ LEFT JOIN {$prefix}feature_lang fl ON fl.id_feature = fp.id_feature AND fl.id_lang = :id_lang /* wybór jakiegokolwiek dostępnego języka dla cechy */ LEFT JOIN ( SELECT id_feature, MIN(id_lang) AS any_lang FROM {$prefix}feature_lang GROUP BY id_feature ) fl_pick ON fl_pick.id_feature = fp.id_feature LEFT JOIN {$prefix}feature_lang fl_any ON fl_any.id_feature = fp.id_feature AND fl_any.id_lang = fl_pick.any_lang /* wartość cechy */ JOIN {$prefix}feature_value fv ON fv.id_feature_value = fp.id_feature_value /* wartość w żądanym języku */ LEFT JOIN {$prefix}feature_value_lang fvl ON fvl.id_feature_value = fv.id_feature_value AND fvl.id_lang = :id_lang /* fallback: jakikolwiek język dla wartości */ LEFT JOIN ( SELECT id_feature_value, MIN(id_lang) AS any_lang FROM {$prefix}feature_value_lang GROUP BY id_feature_value ) fvl_pick ON fvl_pick.id_feature_value = fv.id_feature_value LEFT JOIN {$prefix}feature_value_lang fvl_any ON fvl_any.id_feature_value = fv.id_feature_value AND fvl_any.id_lang = fvl_pick.any_lang WHERE fp.id_product = :id_product ORDER BY feature_name ASC "; $stmt = $pdo->prepare($sql); $stmt->execute([ ':id_lang' => (int)$idLang, ':id_product' => (int)$idProduct, ]); $out = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $fname = trim((string)($row['feature_name'] ?? '')); $fval = trim((string)($row['feature_value'] ?? '')); if ($fname === '' && $fval === '') continue; if ($fname === '') $fname = 'Cecha'; $out[$fname] = $fval; } return $out; } function getProductCombinations(PDO $pdo, $prefix, $idLang, $idShop, $idProduct): array { $sqlComb = " SELECT pa.id_product_attribute, pa.reference AS comb_reference, pa.ean13 AS comb_ean13, pa.weight AS comb_weight, COALESCE(sa.quantity, 0) AS comb_quantity FROM {$prefix}product_attribute pa LEFT JOIN {$prefix}stock_available sa ON sa.id_product = pa.id_product AND sa.id_product_attribute = pa.id_product_attribute AND (sa.id_shop = :id_shop OR sa.id_shop IS NULL) WHERE pa.id_product = :id_product ORDER BY pa.id_product_attribute ASC "; $st = $pdo->prepare($sqlComb); $st->execute([':id_product' => (int)$idProduct, ':id_shop' => (int)$idShop]); $combinations = $st->fetchAll(PDO::FETCH_ASSOC); if (!$combinations) return []; $ids = array_column($combinations, 'id_product_attribute'); $in = implode(',', array_map('intval', $ids)); $sqlAttrs = " SELECT pac.id_product_attribute, agl.name AS group_name, al.name AS attr_name FROM {$prefix}product_attribute_combination pac JOIN {$prefix}attribute a ON a.id_attribute = pac.id_attribute JOIN {$prefix}attribute_lang al ON al.id_attribute = a.id_attribute AND al.id_lang = :id_lang JOIN {$prefix}attribute_group_lang agl ON agl.id_attribute_group = a.id_attribute_group AND agl.id_lang = :id_lang WHERE pac.id_product_attribute IN ($in) ORDER BY agl.name, al.name "; $st2 = $pdo->prepare($sqlAttrs); $st2->execute([':id_lang' => (int)$idLang]); $attrMap = []; while ($r = $st2->fetch(PDO::FETCH_ASSOC)) { $ipa = (int)$r['id_product_attribute']; $pair = trim($r['group_name']) . ": " . trim($r['attr_name']); $attrMap[$ipa][] = $pair; } foreach ($combinations as &$c) { $ipa = (int)$c['id_product_attribute']; $pairs = $attrMap[$ipa] ?? []; $c['attributes_str'] = implode(' | ', $pairs); } return $combinations; } // ===== FUNKCJA PISZĄCA WIERSZE DO CSV ===== function writeProductRowsToCsv($fh, $prod, $featuresStr, $combinations, $delimiter) { if ($combinations) { foreach ($combinations as $c) { $line = [ $prod['id_product'], $c['id_product_attribute'], $prod['product_name'], $prod['manufacturer'], $prod['default_category'], (int)$prod['active'], $prod['price_tax_excl'], $prod['quantity'], $prod['reference'], $prod['ean13'], $prod['weight'], $c['comb_reference'], $c['comb_ean13'], $c['comb_weight'], $c['comb_quantity'], $c['attributes_str'], $featuresStr, ]; fputcsv($fh, $line, $delimiter); } } else { $line = [ $prod['id_product'], 0, $prod['product_name'], $prod['manufacturer'], $prod['default_category'], (int)$prod['active'], $prod['price_tax_excl'], $prod['quantity'], $prod['reference'], $prod['ean13'], $prod['weight'], '', '', '', '', '', // attributes $featuresStr, ]; fputcsv($fh, $line, $delimiter); } } // ===== ZAPYTANIE BAZOWE (wspólne) ===== $baseSelect = " SELECT p.id_product, COALESCE(pl.name, CONCAT('Produkt #', p.id_product)) AS product_name, p.reference, p.ean13, p.weight, ps.price AS price_tax_excl, ps.active, COALESCE(sa.quantity, 0) AS quantity, m.name AS manufacturer, cl.name AS default_category FROM {$prefix}product p /* KLUCZOWA ZMIANA: LEFT JOIN + warunek po id_shop */ LEFT JOIN {$prefix}product_lang pl ON pl.id_product = p.id_product AND pl.id_lang = :id_lang AND pl.id_shop = :id_shop JOIN {$prefix}product_shop ps ON ps.id_product = p.id_product AND ps.id_shop = :id_shop LEFT JOIN {$prefix}stock_available sa ON sa.id_product = p.id_product AND sa.id_product_attribute = 0 AND (sa.id_shop = :id_shop OR sa.id_shop IS NULL) LEFT JOIN {$prefix}manufacturer m ON m.id_manufacturer = p.id_manufacturer LEFT JOIN {$prefix}category_lang cl ON cl.id_category = p.id_category_default AND cl.id_lang = :id_lang "; // ===== TRYB TESTOWY: tylko jeden produkt po id_product lub EAN ===== if ($testProductId || $testEan !== "") { if ($testEan !== "" && !$testProductId) { $stmtId = $pdo->prepare("SELECT id_product FROM {$prefix}product WHERE ean13 = :ean LIMIT 1"); $stmtId->execute([':ean' => $testEan]); $foundId = (int)$stmtId->fetchColumn(); if ($foundId) $testProductId = $foundId; } if (!$testProductId) { fclose($fh); die("Nie znaleziono produktu dla podanego EAN.\n"); } echo "Tryb testowy – eksport tylko produktu id_product={$testProductId}" . ($testEan ? " (EAN={$testEan})" : "") . "\n"; $sqlOne = $baseSelect . " WHERE p.id_product = :pid LIMIT 1"; $stmt = $pdo->prepare($sqlOne); $stmt->bindValue(':id_lang', (int)$idLang, PDO::PARAM_INT); $stmt->bindValue(':id_shop', (int)$idShop, PDO::PARAM_INT); $stmt->bindValue(':pid', (int)$testProductId, PDO::PARAM_INT); $stmt->execute(); $prod = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); if ($prod) { $featuresMap = getProductFeatures($pdo, $prefix, $idLang, (int)$prod['id_product']); $featuresStr = ''; if ($featuresMap) { $pairs = []; foreach ($featuresMap as $k => $v) $pairs[] = trim($k) . ': ' . trim($v); $featuresStr = implode(' | ', $pairs); } $combinations = getProductCombinations($pdo, $prefix, $idLang, $idShop, (int)$prod['id_product']); writeProductRowsToCsv($fh, $prod, $featuresStr, $combinations, $delimiter); echo "✅ Zapisano rekord(y) produktu testowego do CSV.\n"; } else { echo "Brak produktu o id_product={$testProductId}.\n"; } fclose($fh); echo "✅ Zapisano CSV: {$outFile}\n"; exit; } // ===== PEŁNY EKSPORT (paginacja) ===== $sqlCount = "SELECT COUNT(*) FROM {$prefix}product"; $total = (int)$pdo->query($sqlCount)->fetchColumn(); echo "Znaleziono produktów: {$total}\n"; $limit = 1000; $offset = 0; while (true) { $sqlProducts = $baseSelect . " ORDER BY p.id_product ASC LIMIT :limit OFFSET :offset"; $stmt = $pdo->prepare($sqlProducts); $stmt->bindValue(':id_lang', (int)$idLang, PDO::PARAM_INT); $stmt->bindValue(':id_shop', (int)$idShop, PDO::PARAM_INT); $stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT); $stmt->bindValue(':offset', (int)$offset, PDO::PARAM_INT); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt->closeCursor(); if (!$rows) break; foreach ($rows as $prod) { $idProduct = (int)$prod['id_product']; $featuresMap = getProductFeatures($pdo, $prefix, $idLang, $idProduct); $featuresStr = ''; if ($featuresMap) { $pairs = []; foreach ($featuresMap as $k => $v) $pairs[] = trim($k) . ': ' . trim($v); $featuresStr = implode(' | ', $pairs); } $combinations = getProductCombinations($pdo, $prefix, $idLang, $idShop, $idProduct); writeProductRowsToCsv($fh, $prod, $featuresStr, $combinations, $delimiter); } $offset += $limit; echo "Przetworzono: {$offset} / {$total}\n"; } fclose($fh); echo "✅ Zapisano CSV: {$outFile}\n";