Add combined catalog export builder
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
|||||||
# Generated exports
|
# Generated exports
|
||||||
/exports/*
|
/exports/*
|
||||||
!/exports/.gitkeep
|
!/exports/.gitkeep
|
||||||
|
!/exports/catalog-latest.json
|
||||||
|
!/exports/catalog-latest.json.gz
|
||||||
|
|
||||||
# Generated indexes
|
# Generated indexes
|
||||||
/indexes/*
|
/indexes/*
|
||||||
|
|||||||
7
exports/catalog-latest.json
Normal file
7
exports/catalog-latest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"format": "roundcount-catalog",
|
||||||
|
"catalog_version": 1,
|
||||||
|
"generated_at": "2026-07-15T16:19:54+00:00",
|
||||||
|
"product_count": 0,
|
||||||
|
"products": []
|
||||||
|
}
|
||||||
BIN
exports/catalog-latest.json.gz
Normal file
BIN
exports/catalog-latest.json.gz
Normal file
Binary file not shown.
132
tools/build-export.php
Normal file
132
tools/build-export.php
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
$root = dirname(__DIR__);
|
||||||
|
$catalogDir = $root . '/catalog';
|
||||||
|
$exportsDir = $root . '/exports';
|
||||||
|
|
||||||
|
$products = [];
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
if (!is_dir($catalogDir)) {
|
||||||
|
fwrite(STDERR, "Catalog directory not found: {$catalogDir}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_dir($exportsDir) && !mkdir($exportsDir, 0775, true) && !is_dir($exportsDir)) {
|
||||||
|
fwrite(STDERR, "Unable to create exports directory: {$exportsDir}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = new RecursiveIteratorIterator(
|
||||||
|
new RecursiveDirectoryIterator(
|
||||||
|
$catalogDir,
|
||||||
|
FilesystemIterator::SKIP_DOTS
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
if (!$file->isFile() || strtolower($file->getExtension()) !== 'json') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $file->getPathname();
|
||||||
|
$relativePath = substr($path, strlen($root) + 1);
|
||||||
|
|
||||||
|
$raw = file_get_contents($path);
|
||||||
|
|
||||||
|
if ($raw === false) {
|
||||||
|
$errors[] = "{$relativePath}: unable to read file";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$record = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
} catch (JsonException $exception) {
|
||||||
|
$errors[] = "{$relativePath}: invalid JSON: {$exception->getMessage()}";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($record)) {
|
||||||
|
$errors[] = "{$relativePath}: root value must be an object";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$record['_catalog_path'] = $relativePath;
|
||||||
|
$products[] = $record;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($errors !== []) {
|
||||||
|
fwrite(STDERR, "Export build failed:\n\n");
|
||||||
|
|
||||||
|
foreach ($errors as $error) {
|
||||||
|
fwrite(STDERR, " - {$error}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
usort(
|
||||||
|
$products,
|
||||||
|
static function (array $left, array $right): int {
|
||||||
|
$leftManufacturer = strtolower((string) ($left['manufacturer'] ?? ''));
|
||||||
|
$rightManufacturer = strtolower((string) ($right['manufacturer'] ?? ''));
|
||||||
|
|
||||||
|
$manufacturerCompare = $leftManufacturer <=> $rightManufacturer;
|
||||||
|
|
||||||
|
if ($manufacturerCompare !== 0) {
|
||||||
|
return $manufacturerCompare;
|
||||||
|
}
|
||||||
|
|
||||||
|
$leftName = strtolower((string) ($left['product_name'] ?? ''));
|
||||||
|
$rightName = strtolower((string) ($right['product_name'] ?? ''));
|
||||||
|
|
||||||
|
return $leftName <=> $rightName;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$export = [
|
||||||
|
'format' => 'roundcount-catalog',
|
||||||
|
'catalog_version' => 1,
|
||||||
|
'generated_at' => gmdate('c'),
|
||||||
|
'product_count' => count($products),
|
||||||
|
'products' => $products,
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$json = json_encode(
|
||||||
|
$export,
|
||||||
|
JSON_PRETTY_PRINT |
|
||||||
|
JSON_UNESCAPED_SLASHES |
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
) . PHP_EOL;
|
||||||
|
} catch (JsonException $exception) {
|
||||||
|
fwrite(STDERR, "Unable to encode catalog export: {$exception->getMessage()}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$jsonPath = $exportsDir . '/catalog-latest.json';
|
||||||
|
$gzipPath = $exportsDir . '/catalog-latest.json.gz';
|
||||||
|
|
||||||
|
if (file_put_contents($jsonPath, $json) === false) {
|
||||||
|
fwrite(STDERR, "Unable to write {$jsonPath}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$compressed = gzencode($json, 9);
|
||||||
|
|
||||||
|
if ($compressed === false) {
|
||||||
|
fwrite(STDERR, "Unable to compress catalog export\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_put_contents($gzipPath, $compressed) === false) {
|
||||||
|
fwrite(STDERR, "Unable to write {$gzipPath}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Catalog export complete.\n";
|
||||||
|
echo "Products exported: " . count($products) . "\n";
|
||||||
|
echo "JSON: exports/catalog-latest.json\n";
|
||||||
|
echo "Gzip: exports/catalog-latest.json.gz\n";
|
||||||
Reference in New Issue
Block a user