Start MySQL implementation: config template, PDO layer and migrations
This commit is contained in:
parent
e22476da57
commit
883ff30877
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -15,6 +15,7 @@ Thumbs.db
|
||||||
|
|
||||||
# Local secrets
|
# Local secrets
|
||||||
deploy-config.php
|
deploy-config.php
|
||||||
|
config.php
|
||||||
|
|
||||||
# Logs/temp
|
# Logs/temp
|
||||||
*.log
|
*.log
|
||||||
|
|
|
||||||
21
README.md
21
README.md
|
|
@ -55,6 +55,27 @@ photo-gallery/
|
||||||
php -S 127.0.0.1:8080
|
php -S 127.0.0.1:8080
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## MySQL конфиг и миграции (этап перехода на БД)
|
||||||
|
|
||||||
|
1. Создай локальный конфиг из шаблона:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp config.php.example config.php
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Заполни доступы к MySQL в `config.php`.
|
||||||
|
|
||||||
|
3. Прогони миграции:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php scripts/migrate.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Файлы:
|
||||||
|
- `lib/db.php` — подключение PDO
|
||||||
|
- `migrations/*.sql` — схема БД
|
||||||
|
- `scripts/migrate.php` — runner миграций
|
||||||
|
|
||||||
Открыть в браузере:
|
Открыть в браузере:
|
||||||
|
|
||||||
- `http://127.0.0.1:8080`
|
- `http://127.0.0.1:8080`
|
||||||
|
|
|
||||||
11
config.php.example
Normal file
11
config.php.example
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'db' => [
|
||||||
|
'host' => '127.0.0.1',
|
||||||
|
'port' => 3306,
|
||||||
|
'name' => 'photo_gallery',
|
||||||
|
'user' => 'gallery_user',
|
||||||
|
'pass' => 'change_me',
|
||||||
|
'charset' => 'utf8mb4',
|
||||||
|
],
|
||||||
|
];
|
||||||
47
lib/db.php
Normal file
47
lib/db.php
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function appConfig(): array
|
||||||
|
{
|
||||||
|
static $cfg = null;
|
||||||
|
if ($cfg !== null) {
|
||||||
|
return $cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = __DIR__ . '/../config.php';
|
||||||
|
if (!is_file($path)) {
|
||||||
|
throw new RuntimeException('config.php not found. Copy config.php.example');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cfg = require $path;
|
||||||
|
if (!is_array($cfg)) {
|
||||||
|
throw new RuntimeException('Invalid config.php format');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function db(): PDO
|
||||||
|
{
|
||||||
|
static $pdo = null;
|
||||||
|
if ($pdo instanceof PDO) {
|
||||||
|
return $pdo;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = appConfig()['db'] ?? [];
|
||||||
|
$host = $db['host'] ?? '127.0.0.1';
|
||||||
|
$port = (int)($db['port'] ?? 3306);
|
||||||
|
$name = $db['name'] ?? '';
|
||||||
|
$user = $db['user'] ?? '';
|
||||||
|
$pass = $db['pass'] ?? '';
|
||||||
|
$charset = $db['charset'] ?? 'utf8mb4';
|
||||||
|
|
||||||
|
$dsn = "mysql:host={$host};port={$port};dbname={$name};charset={$charset}";
|
||||||
|
$pdo = new PDO($dsn, (string)$user, (string)$pass, [
|
||||||
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $pdo;
|
||||||
|
}
|
||||||
54
migrations/001_init.sql
Normal file
54
migrations/001_init.sql
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS sections (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
sort_order INT NOT NULL DEFAULT 1000,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY uq_sections_name (name)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS photos (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
section_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
code_name VARCHAR(191) NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
sort_order INT NOT NULL DEFAULT 1000,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT fk_photos_section FOREIGN KEY (section_id) REFERENCES sections(id) ON DELETE CASCADE,
|
||||||
|
UNIQUE KEY uq_photos_code_name (code_name),
|
||||||
|
KEY idx_photos_section_sort (section_id, sort_order)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS photo_files (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
photo_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
kind ENUM('before','after') NOT NULL,
|
||||||
|
file_path VARCHAR(500) NOT NULL,
|
||||||
|
mime_type VARCHAR(100) NOT NULL,
|
||||||
|
size_bytes INT UNSIGNED NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT fk_photo_files_photo FOREIGN KEY (photo_id) REFERENCES photos(id) ON DELETE CASCADE,
|
||||||
|
UNIQUE KEY uq_photo_files_kind (photo_id, kind)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS comment_users (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
display_name VARCHAR(191) NOT NULL,
|
||||||
|
token_hash CHAR(64) NOT NULL,
|
||||||
|
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY uq_comment_users_token_hash (token_hash)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS photo_comments (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
photo_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
user_id BIGINT UNSIGNED NULL,
|
||||||
|
comment_text TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT fk_photo_comments_photo FOREIGN KEY (photo_id) REFERENCES photos(id) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT fk_photo_comments_user FOREIGN KEY (user_id) REFERENCES comment_users(id) ON DELETE SET NULL,
|
||||||
|
KEY idx_photo_comments_photo_created (photo_id, created_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
48
scripts/migrate.php
Executable file
48
scripts/migrate.php
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require __DIR__ . '/../lib/db.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
fwrite(STDERR, "DB connection failed: " . $e->getMessage() . PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->exec('CREATE TABLE IF NOT EXISTS migrations (name VARCHAR(191) PRIMARY KEY, applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci');
|
||||||
|
|
||||||
|
$files = glob(__DIR__ . '/../migrations/*.sql') ?: [];
|
||||||
|
sort($files, SORT_NATURAL);
|
||||||
|
|
||||||
|
$check = $pdo->prepare('SELECT 1 FROM migrations WHERE name = :name');
|
||||||
|
$mark = $pdo->prepare('INSERT INTO migrations(name) VALUES (:name)');
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$name = basename($file);
|
||||||
|
$check->execute(['name' => $name]);
|
||||||
|
if ($check->fetchColumn()) {
|
||||||
|
echo "skip {$name}" . PHP_EOL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "apply {$name}" . PHP_EOL;
|
||||||
|
$sql = file_get_contents($file);
|
||||||
|
if ($sql === false) {
|
||||||
|
throw new RuntimeException("Cannot read {$file}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
$pdo->exec($sql);
|
||||||
|
$mark->execute(['name' => $name]);
|
||||||
|
$pdo->commit();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "done" . PHP_EOL;
|
||||||
Loading…
Reference in New Issue
Block a user