https://dev.vitec.com/product-audit/ * * Plain PDO against config/system/settings.php (pattern * migrations/check_bg.php), re-run any time the data changes: * * php migrations/build_product_audit.php */ error_reporting(E_ALL); ini_set('display_errors', '1'); $root = null; $dir = __DIR__; for ($i = 0; $i < 5; $i++) { if (is_file($dir . '/config/system/settings.php')) { $root = $dir; break; } $dir = dirname($dir); } if ($root === null) { exit("Could not locate project root above " . __DIR__ . "\n"); } $settings = require $root . '/config/system/settings.php'; $db = $settings['DB']['Connections']['Default']; $pdo = new PDO( sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4', $db['host'] ?? 'localhost', $db['port'] ?? 3306, $db['dbname'] ?? ''), $db['user'] ?? '', $db['password'] ?? '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] ); // ---- data ----------------------------------------------------------------- $products = $pdo->query( "SELECT uid, title, slug, teaser, subtitle, description, description2, highlights, capabilities, applications, resources, resources_layout, datasheets, solutions, hidden, legacy, supportproduct, subproduct, hideonwebsite, hideonproducts, showdatapath FROM tx_vitec_domain_model_product WHERE deleted = 0 ORDER BY title" )->fetchAll(); $refs = $pdo->query( "SELECT r.uid_foreign, r.fieldname, COUNT(*) AS cnt, MIN(r.sorting_foreign) AS minsort FROM sys_file_reference r WHERE r.deleted = 0 AND r.hidden = 0 AND r.tablenames = 'tx_vitec_domain_model_product' AND r.fieldname IN ('heroimage','productimage','ogimage','videofile') GROUP BY r.uid_foreign, r.fieldname" )->fetchAll(); $refCount = []; foreach ($refs as $r) { $refCount[(int)$r['uid_foreign']][$r['fieldname']] = (int)$r['cnt']; } // first thumbnail per product: prefer a product photo, fall back to the hero $thumbRows = $pdo->query( "SELECT r.uid_foreign, r.fieldname, f.identifier FROM sys_file_reference r JOIN sys_file f ON f.uid = r.uid_local WHERE r.deleted = 0 AND r.hidden = 0 AND r.tablenames = 'tx_vitec_domain_model_product' AND r.fieldname IN ('heroimage','productimage') ORDER BY r.uid_foreign, FIELD(r.fieldname,'productimage','heroimage'), r.sorting_foreign" )->fetchAll(); $thumb = []; foreach ($thumbRows as $r) { $uid = (int)$r['uid_foreign']; if (!isset($thumb[$uid])) { $thumb[$uid] = '/fileadmin' . $r['identifier']; } } // ---- helpers ---------------------------------------------------------------- function h(string $v): string { return htmlspecialchars($v, ENT_QUOTES | ENT_HTML5); } function badge(string $label, bool $ok, string $detail = ''): string { $cls = $ok ? 'ok' : 'miss'; $txt = $label . ($detail !== '' ? ' ' . $detail : ''); return '' . h($txt) . ''; } // ---- stats ------------------------------------------------------------------ $total = count($products); $stat = ['hero' => 0, 'photo' => 0, 'teaser' => 0, 'highlights' => 0, 'description' => 0, 'resources' => 0, 'datasheets' => 0, 'solutions' => 0]; foreach ($products as $p) { $uid = (int)$p['uid']; if (($refCount[$uid]['heroimage'] ?? 0) > 0) { $stat['hero']++; } if (($refCount[$uid]['productimage'] ?? 0) > 0) { $stat['photo']++; } if (trim((string)$p['teaser']) !== '') { $stat['teaser']++; } if (trim((string)$p['highlights']) !== '') { $stat['highlights']++; } if (trim((string)$p['description']) !== '') { $stat['description']++; } if ((int)$p['resources'] > 0) { $stat['resources']++; } if ((int)$p['datasheets'] > 0) { $stat['datasheets']++; } if ((int)$p['solutions'] > 0) { $stat['solutions']++; } } // ---- rows ------------------------------------------------------------------- $rowsHtml = ''; foreach ($products as $p) { $uid = (int)$p['uid']; $hero = $refCount[$uid]['heroimage'] ?? 0; $photos = $refCount[$uid]['productimage'] ?? 0; $og = $refCount[$uid]['ogimage'] ?? 0; $video = $refCount[$uid]['videofile'] ?? 0; $hasTeaser = trim((string)$p['teaser']) !== ''; $hasHighlights = trim((string)$p['highlights']) !== ''; $hasDescription = trim((string)$p['description']) !== ''; $classes = ['row']; if ($hero === 0) { $classes[] = 'f-nohero'; } if ($photos === 0) { $classes[] = 'f-nophoto'; } if (!$hasTeaser) { $classes[] = 'f-noteaser'; } if (!$hasHighlights) { $classes[] = 'f-nohighlights'; } if ((int)$p['legacy'] === 1) { $classes[] = 'f-legacy'; } if ((int)$p['hidden'] === 1 || (int)$p['hideonwebsite'] === 1) { $classes[] = 'f-hidden'; } $flags = []; foreach (['hidden' => 'hidden', 'legacy' => 'legacy', 'supportproduct' => 'support', 'subproduct' => 'sub', 'hideonwebsite' => 'hideWeb', 'hideonproducts' => 'hideList', 'showdatapath' => 'datapath'] as $col => $label) { if ((int)$p[$col] === 1) { $flags[] = '' . $label . ''; } } $img = isset($thumb[$uid]) ? '' : '
no image
'; $slug = trim((string)$p['slug'], '/'); $rowsHtml .= '
' . '
' . $img . '
' . '
' . '' . '
' . badge('Hero', $hero > 0, $hero > 1 ? '(' . $hero . '!)' : '') . badge('Photos', $photos > 0, (string)($photos ?: '')) . badge('Teaser', $hasTeaser) . badge('Description', $hasDescription) . badge('Highlights', $hasHighlights) . badge('Resources', (int)$p['resources'] > 0, (string)((int)$p['resources'] ?: '')) . badge('Datasheets', (int)$p['datasheets'] > 0, (string)((int)$p['datasheets'] ?: '')) . badge('Solutions', (int)$p['solutions'] > 0, (string)((int)$p['solutions'] ?: '')) . badge('OG', $og > 0) . badge('Video', $video > 0) . '' . h((string)$p['resources_layout']) . '' . implode('', $flags) . '
' . "\n"; } // ---- page ------------------------------------------------------------------- $generated = date('Y-m-d H:i'); $statLine = sprintf( 'Hero %d/%d · Photos %d/%d · Teaser %d/%d · Description %d/%d · Highlights %d/%d · Resources %d/%d · Datasheets %d/%d · Solutions %d/%d', $stat['hero'], $total, $stat['photo'], $total, $stat['teaser'], $total, $stat['description'], $total, $stat['highlights'], $total, $stat['resources'], $total, $stat['datasheets'], $total, $stat['solutions'], $total ); $html = '' . '' . '' . 'VITEC Product Audit' . '

VITEC Product Audit (' . $total . ' records, generated ' . $generated . ')

' . '
' . h($statLine) . '
' . '
' . '' . '' . '' . '' . '' . '' . '' . '
' . "\n" . $rowsHtml . '
' . ''; $outDir = $root . '/public/product-audit'; if (!is_dir($outDir)) { mkdir($outDir, 0775, true); } file_put_contents($outDir . '/index.html', $html); echo "geschrieben: public/product-audit/index.html ($total Produkte)\n"; echo "-> https://dev.vitec.com/product-audit/\n";