| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/admin/ |
Upload File : |
<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/includes/functions.php';
require_admin_role();
$message = [];
$warnings = [];
$error = '';
$changes = [
'menus' => [
'menu_type' => "ALTER TABLE menus ADD COLUMN menu_type ENUM('food','soft','wine') NOT NULL DEFAULT 'food'",
],
'menu_categories' => [
'name_en' => 'ALTER TABLE menu_categories ADD COLUMN name_en VARCHAR(150) DEFAULT NULL',
'name_es' => 'ALTER TABLE menu_categories ADD COLUMN name_es VARCHAR(150) DEFAULT NULL',
'name_de' => 'ALTER TABLE menu_categories ADD COLUMN name_de VARCHAR(150) DEFAULT NULL',
],
'menu_items' => [
'name_en' => 'ALTER TABLE menu_items ADD COLUMN name_en VARCHAR(255) DEFAULT NULL',
'name_es' => 'ALTER TABLE menu_items ADD COLUMN name_es VARCHAR(255) DEFAULT NULL',
'name_de' => 'ALTER TABLE menu_items ADD COLUMN name_de VARCHAR(255) DEFAULT NULL',
'description_en' => 'ALTER TABLE menu_items ADD COLUMN description_en TEXT DEFAULT NULL',
'description_es' => 'ALTER TABLE menu_items ADD COLUMN description_es TEXT DEFAULT NULL',
'description_de' => 'ALTER TABLE menu_items ADD COLUMN description_de TEXT DEFAULT NULL',
'ingredients_en' => 'ALTER TABLE menu_items ADD COLUMN ingredients_en TEXT DEFAULT NULL',
'ingredients_es' => 'ALTER TABLE menu_items ADD COLUMN ingredients_es TEXT DEFAULT NULL',
'ingredients_de' => 'ALTER TABLE menu_items ADD COLUMN ingredients_de TEXT DEFAULT NULL',
'allergens_en' => 'ALTER TABLE menu_items ADD COLUMN allergens_en VARCHAR(500) DEFAULT NULL',
'allergens_es' => 'ALTER TABLE menu_items ADD COLUMN allergens_es VARCHAR(500) DEFAULT NULL',
'allergens_de' => 'ALTER TABLE menu_items ADD COLUMN allergens_de VARCHAR(500) DEFAULT NULL',
],
'blog_posts' => [
'title_en' => 'ALTER TABLE blog_posts ADD COLUMN title_en VARCHAR(255) DEFAULT NULL',
'excerpt_en' => 'ALTER TABLE blog_posts ADD COLUMN excerpt_en TEXT DEFAULT NULL',
'content_en' => 'ALTER TABLE blog_posts ADD COLUMN content_en MEDIUMTEXT DEFAULT NULL',
'title_es' => 'ALTER TABLE blog_posts ADD COLUMN title_es VARCHAR(255) DEFAULT NULL',
'excerpt_es' => 'ALTER TABLE blog_posts ADD COLUMN excerpt_es TEXT DEFAULT NULL',
'content_es' => 'ALTER TABLE blog_posts ADD COLUMN content_es MEDIUMTEXT DEFAULT NULL',
'title_de' => 'ALTER TABLE blog_posts ADD COLUMN title_de VARCHAR(255) DEFAULT NULL',
'excerpt_de' => 'ALTER TABLE blog_posts ADD COLUMN excerpt_de TEXT DEFAULT NULL',
'content_de' => 'ALTER TABLE blog_posts ADD COLUMN content_de MEDIUMTEXT DEFAULT NULL',
],
];
/**
* Preserve existing ENUM values instead of narrowing the type.
* We only append 'wine' to the existing list when it is missing.
*/
function polana_repair_wine_enum(): string
{
$stmt = db()->query("SHOW COLUMNS FROM `menus` LIKE 'menu_type'");
$column = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$column) {
throw new RuntimeException('Brak kolumny menus.menu_type — migracja nie została ukończona.');
}
$type = (string)($column['Type'] ?? '');
if (!preg_match('/^enum\((.*)\)$/is', $type, $matches)) {
return 'Kolumna menu_type ma typ ' . $type . ' — bez wymuszonej zmiany istniejącego typu.';
}
preg_match_all("/'([a-z][a-z0-9_]*)'/i", $matches[1], $values);
$enumValues = $values[1];
$expected = implode(',', array_map(static fn($v) => "'" . $v . "'", $enumValues));
if (preg_replace('/\s+/', '', $matches[1]) !== $expected) {
throw new RuntimeException('Nieobsługiwana definicja ENUM menu_type. Wymagana kontrola administratora bazy.');
}
// Reject unknown/unsafe definitions: an administrator can repair those manually.
if (!$enumValues || count(array_unique($enumValues)) !== count($enumValues) ||
array_filter($enumValues, static fn($v) => !preg_match('/^[a-z][a-z0-9_]{0,39}$/D', $v))) {
throw new RuntimeException('Nietypowa definicja ENUM menu_type: wymaga ręcznej kontroli bazy.');
}
if (in_array('wine', $enumValues, true)) {
return 'menus.menu_type: wartość wine jest już obsługiwana';
}
$enumValues[] = 'wine';
$sqlValues = implode(',', array_map(static fn($v) => db()->quote($v), $enumValues));
$nullable = strtoupper((string)($column['Null'] ?? 'NO')) === 'YES';
$sql = 'ALTER TABLE `menus` MODIFY COLUMN `menu_type` ENUM(' . $sqlValues . ') ';
$sql .= $nullable ? 'NULL' : 'NOT NULL';
if (($column['Default'] ?? null) !== null) {
$sql .= ' DEFAULT ' . db()->quote((string)$column['Default']);
} elseif ($nullable) {
$sql .= ' DEFAULT NULL';
}
db()->exec($sql);
return 'menus.menu_type: rozszerzono ENUM o wine (istniejące wartości zachowane)';
}
function polana_wine_schema_status(): string
{
try {
$stmt = db()->query("SHOW COLUMNS FROM `menus` LIKE 'menu_type'");
$column = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$column) return 'Brak kolumny menu_type — uruchom migrację';
$type = (string)($column['Type'] ?? '');
if (preg_match('/^enum\((.*)\)$/is', $type, $m)) {
preg_match_all("/'([^']+)'/", $m[1], $matches);
if (!in_array('wine', $matches[1], true)) {
return 'Brakuje wartości wine w ENUM: ' . $type . ' — uruchom migrację';
}
}
$check = [
'menu_categories' => ['name_en'],
'menu_items' => ['name_en','description_en','ingredients_en','allergens_en'],
];
foreach ($check as $table => $cols) {
foreach ($cols as $col) {
$has = db()->query("SHOW COLUMNS FROM `$table` LIKE " . db()->quote($col))->fetchColumn();
if ($has === false) return "Brak $table.$col — uruchom migrację";
}
}
return 'Weryfikacja OK: możliwe tworzenie i edycja kart win oraz wpisów PL/EN';
} catch (Throwable $e) {
error_log('[POLANA_WINE_SCHEMA_CHECK] ' . $e->getMessage());
return 'Nie udało się sprawdzić schematu. Zobacz log PHP.';
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
foreach ($changes as $table => $columns) {
if ($table === 'blog_posts') {
try {
ensure_blog_schema();
} catch (Throwable $e) {
$warnings[] = 'Moduł bloga: nie udało się przygotować schematu (' . $e->getCode() . ').';
error_log('[POLANA_BILINGUAL_BLOG] ' . $e->getMessage());
continue; // Blog must not prevent fixing wine cards.
}
}
foreach ($columns as $column => $ddl) {
try {
$existing = db()->query("SHOW COLUMNS FROM `$table` LIKE " . db()->quote($column))->fetchAll();
if ($existing) {
$message[] = "$table.$column: już istnieje";
} else {
db()->exec($ddl);
$message[] = "$table.$column: dodano";
}
} catch (Throwable $e) {
error_log('[POLANA_BILINGUAL_MIGRATE] ' . $table . '.' . $column . ': ' . $e->getMessage());
$warnings[] = "$table.$column: nie udało się wykonać zmiany (kod " . (string)$e->getCode() . ").";
}
}
}
try {
polana_site_translation_create();
$message[] = 'polana_site_translations: tabela szkiców i zatwierdzonych tłumaczeń dostępna';
} catch (Throwable $e) {
error_log('[POLANA_SITE_I18N_MIGRATE] '.$e->getMessage());
$warnings[] = 'Nie udało się utworzyć tabeli polana_site_translations (kod '.(string)$e->getCode().').';
}
try {
$message[] = polana_repair_wine_enum();
} catch (Throwable $e) {
error_log('[POLANA_WINE_ENUM] ' . $e->getMessage());
$warnings[] = 'menus.menu_type: nie udało się rozszerzyć dopuszczalnych wartości o wine. Sprawdź uprawnienia ALTER i log PHP.';
}
}
$status = polana_wine_schema_status();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try { polana_site_multi_create(); $message[]='Tabela tłumaczeń strony ES/DE: gotowa'; }
catch (Throwable $e) {error_log('[POLANA_R7_TRANSLATIONS] '.$e->getMessage());$warnings[]='Nie udało się utworzyć tabeli tłumaczeń ES/DE.';}
}
render_admin_header('Migracja PL/EN / karta win');
?>
<div class="admin-title-row">
<div><h1>PL/EN/ES/DE — migracja wielojęzyczna</h1><p>Naprawia zapis rodzaju karty „Wina”, jeśli w ENUM zabrakło wartości wine.</p></div>
</div>
<section class="form-card">
<p><strong>Przed uruchomieniem wykonaj kopię bazy MariaDB.</strong> Migracja dodaje brakujące kolumny i ewentualnie rozszerza dozwolone wartości menu_type; nie usuwa żadnych kart ani pozycji.</p>
<p><strong>Stan schematu:</strong> <?= e($status) ?></p>
<p><strong>Wersje EN strony:</strong> <?= polana_site_translation_ready() ? 'Tabela szkiców i publikacji gotowa.' : 'Brak tabeli tłumaczeń WWW — uruchom migrację.' ?></p>
<p><a href="/admin/translate-site.php">🇬🇧 Tłumaczenie strony / Docker</a></p>
<?php if ($error): ?><div class="alert alert-error"><?= e($error) ?></div><?php endif; ?>
<?php foreach ($warnings as $line): ?><div class="alert alert-error"><?= e($line) ?></div><?php endforeach; ?>
<?php foreach ($message as $line): ?><p><?= e($line) ?></p><?php endforeach; ?>
<form method="post"><?= csrf_field() ?><button class="btn btn-primary" type="submit">Sprawdź i napraw karty PL/EN/ES/DE</button></form>
<p><a href="/admin/menus.php">← Wróć do kart menu</a></p>
</section>
<?php render_admin_footer(); ?>