Refactor database handling to require PostgreSQL connection, removing fallback to JSON. Implement error handling for database unavailability in key files. Update .env.example to reflect mandatory DATABASE_URL for local development. Remove Firebase configuration and related code from the project.
This commit is contained in:
+13
-7
@@ -18,20 +18,26 @@ if (!$url) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$pdo = get_db_connection();
|
||||
if (!$pdo) {
|
||||
fwrite(STDERR, "Keine DB-Verbindung zu: {$url}\n");
|
||||
try {
|
||||
$pdo = require_database();
|
||||
} catch (DatabaseUnavailableException $e) {
|
||||
fwrite(STDERR, $e->getMessage() . "\n");
|
||||
fwrite(STDERR, "Prüfe: Docker läuft? docker compose -f docker-compose.dev.yml ps\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
init_db();
|
||||
|
||||
$count = (int) $pdo->query('SELECT COUNT(*) FROM recipes')->fetchColumn();
|
||||
echo "Verbindung OK. Rezepte in DB: {$count}\n";
|
||||
|
||||
if ($count > 0) {
|
||||
$stmt = $pdo->query("SELECT slug, data->'i18n'->'en'->>'title' AS title FROM recipes LIMIT 5");
|
||||
if ($count === 0) {
|
||||
echo "Hinweis: Leere DB – einmalig seeden mit: php scripts/db-seed.php\n";
|
||||
} else {
|
||||
$stmt = $pdo->query(
|
||||
"SELECT r.slug, t.title
|
||||
FROM recipes r
|
||||
LEFT JOIN recipe_translations t ON t.recipe_slug = r.slug AND t.lang = 'en'
|
||||
LIMIT 5"
|
||||
);
|
||||
echo "\nBeispiel-Zeilen:\n";
|
||||
while ($row = $stmt->fetch()) {
|
||||
echo " - {$row['slug']}: {$row['title']}\n";
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* Einmaliger Import aus data/recipes.json in die relationale DB.
|
||||
* Die Website liest zur Laufzeit nur noch aus Postgres.
|
||||
*
|
||||
* php scripts/db-seed.php
|
||||
*/
|
||||
require_once dirname(__DIR__) . '/helpers.php';
|
||||
|
||||
$seedPath = dirname(__DIR__) . '/data/recipes.json';
|
||||
if (!file_exists($seedPath)) {
|
||||
fwrite(STDERR, "Seed-Datei fehlt: data/recipes.json\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$raw = file_get_contents($seedPath);
|
||||
$recipes = json_decode($raw, true);
|
||||
if (!is_array($recipes)) {
|
||||
fwrite(STDERR, "Ungültiges JSON in data/recipes.json\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = require_database();
|
||||
} catch (DatabaseUnavailableException $e) {
|
||||
fwrite(STDERR, $e->getMessage() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
foreach ($recipes as $recipe) {
|
||||
if (!is_array($recipe) || empty($recipe['slug'])) {
|
||||
continue;
|
||||
}
|
||||
if (save_recipe($recipe, $pdo)) {
|
||||
$count++;
|
||||
echo " + {$recipe['slug']}\n";
|
||||
} else {
|
||||
fwrite(STDERR, " ! Fehler bei {$recipe['slug']}\n");
|
||||
}
|
||||
}
|
||||
|
||||
echo "\nImport abgeschlossen: {$count} Rezepte.\n";
|
||||
@@ -0,0 +1,70 @@
|
||||
-- FlixCooks relational recipe schema (PostgreSQL)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipes (
|
||||
slug VARCHAR(255) PRIMARY KEY,
|
||||
hero TEXT NOT NULL DEFAULT '',
|
||||
prep_time INTEGER NOT NULL DEFAULT 0,
|
||||
cook_time INTEGER NOT NULL DEFAULT 0,
|
||||
total_time INTEGER NOT NULL DEFAULT 0,
|
||||
servings INTEGER NOT NULL DEFAULT 2,
|
||||
featured BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
coming_soon BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
calories INTEGER NOT NULL DEFAULT 0,
|
||||
protein INTEGER NOT NULL DEFAULT 0,
|
||||
carbs INTEGER NOT NULL DEFAULT 0,
|
||||
fat INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe_translations (
|
||||
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
|
||||
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
|
||||
title TEXT NOT NULL DEFAULT '',
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
category TEXT NOT NULL DEFAULT '',
|
||||
difficulty TEXT NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (recipe_slug, lang)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe_tags (
|
||||
id SERIAL PRIMARY KEY,
|
||||
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
|
||||
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
|
||||
tag TEXT NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_recipe_tags_slug_lang ON recipe_tags (recipe_slug, lang);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe_ingredients (
|
||||
id SERIAL PRIMARY KEY,
|
||||
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
|
||||
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
|
||||
content TEXT NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_recipe_ingredients_slug_lang ON recipe_ingredients (recipe_slug, lang);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe_utensils (
|
||||
id SERIAL PRIMARY KEY,
|
||||
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
|
||||
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
|
||||
content TEXT NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_recipe_utensils_slug_lang ON recipe_utensils (recipe_slug, lang);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe_steps (
|
||||
id SERIAL PRIMARY KEY,
|
||||
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
|
||||
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
video_url TEXT NOT NULL DEFAULT '',
|
||||
timer_minutes INTEGER,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_recipe_steps_slug_lang ON recipe_steps (recipe_slug, lang);
|
||||
Reference in New Issue
Block a user