16235369cb
Highlights include configurable menus, specials, cart/checkout, taxes, customer accounts with email 2FA, newsletters, analytics, refunds, PDF/CSV exports, Square/Mailgun adapters, and optional MySQL migration. See README.md for setup and production configuration. Verified PHP/JavaScript syntax, responsive layouts, registration, 2FA, checkout, dashboard workflows, settings persistence, and PDF generation. Real Square, Mailgun, and MySQL connections require credentials/server access. Square implementation follows the official Payments API and Refunds API.
98 lines
4.0 KiB
PHP
98 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace FatBottom\Services;
|
|
|
|
use FatBottom\Core\Config;
|
|
use PDO;
|
|
use RuntimeException;
|
|
|
|
final class MySqlMigrator
|
|
{
|
|
public function __construct(private readonly Config $config)
|
|
{
|
|
}
|
|
|
|
public function migrate(): array
|
|
{
|
|
$sqlitePath = BASE_PATH . '/storage/database/store.sqlite';
|
|
if (!is_file($sqlitePath)) {
|
|
throw new RuntimeException('The SQLite store database does not exist yet.');
|
|
}
|
|
if (!extension_loaded('pdo_mysql')) {
|
|
throw new RuntimeException('The pdo_mysql PHP extension is required for migration.');
|
|
}
|
|
|
|
$mysql = new PDO(
|
|
sprintf(
|
|
'mysql:host=%s;port=%d;charset=utf8mb4',
|
|
$this->config->get('database.mysql_host'),
|
|
(int) $this->config->get('database.mysql_port', 3306)
|
|
),
|
|
(string) $this->config->get('database.mysql_username'),
|
|
(string) $this->config->get('database.mysql_password'),
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
|
|
);
|
|
$database = preg_replace('/[^a-zA-Z0-9_]/', '', (string) $this->config->get('database.mysql_database'));
|
|
if ($database === '') {
|
|
throw new RuntimeException('Enter a valid MySQL database name.');
|
|
}
|
|
$mysql->exec("CREATE DATABASE IF NOT EXISTS `{$database}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
|
$mysql->exec("USE `{$database}`");
|
|
|
|
$sqlite = new PDO('sqlite:' . $sqlitePath, null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
$tables = $sqlite->query(
|
|
"SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name"
|
|
)->fetchAll(PDO::FETCH_COLUMN);
|
|
$rowCount = 0;
|
|
|
|
$mysql->exec('SET FOREIGN_KEY_CHECKS = 0');
|
|
foreach ($tables as $table) {
|
|
$columns = $sqlite->query("PRAGMA table_info(`{$table}`)")->fetchAll(PDO::FETCH_ASSOC);
|
|
$definitions = [];
|
|
$primary = [];
|
|
foreach ($columns as $column) {
|
|
$type = strtoupper((string) $column['type']);
|
|
$mysqlType = str_contains($type, 'INT') ? 'BIGINT'
|
|
: (str_contains($type, 'REAL') || str_contains($type, 'FLOA') ? 'DOUBLE' : 'TEXT');
|
|
if ((int) $column['pk'] === 1 && $column['name'] === 'id') {
|
|
$definitions[] = '`id` BIGINT NOT NULL AUTO_INCREMENT';
|
|
$primary[] = '`id`';
|
|
} else {
|
|
$definitions[] = sprintf(
|
|
'`%s` %s %s',
|
|
str_replace('`', '', (string) $column['name']),
|
|
$mysqlType,
|
|
(int) $column['notnull'] === 1 ? 'NOT NULL' : 'NULL'
|
|
);
|
|
if ((int) $column['pk'] === 1) {
|
|
$primary[] = '`' . str_replace('`', '', (string) $column['name']) . '`';
|
|
}
|
|
}
|
|
}
|
|
if ($primary !== []) {
|
|
$definitions[] = 'PRIMARY KEY (' . implode(', ', $primary) . ')';
|
|
}
|
|
$mysql->exec("DROP TABLE IF EXISTS `{$table}`");
|
|
$mysql->exec("CREATE TABLE `{$table}` (" . implode(', ', $definitions) . ') ENGINE=InnoDB');
|
|
|
|
$rows = $sqlite->query("SELECT * FROM `{$table}`")->fetchAll(PDO::FETCH_ASSOC);
|
|
if ($rows !== []) {
|
|
$names = array_keys($rows[0]);
|
|
$placeholders = implode(', ', array_fill(0, count($names), '?'));
|
|
$quotedNames = implode(', ', array_map(static fn (string $name): string => "`{$name}`", $names));
|
|
$insert = $mysql->prepare("INSERT INTO `{$table}` ({$quotedNames}) VALUES ({$placeholders})");
|
|
foreach ($rows as $row) {
|
|
$insert->execute(array_values($row));
|
|
$rowCount++;
|
|
}
|
|
}
|
|
}
|
|
$mysql->exec('SET FOREIGN_KEY_CHECKS = 1');
|
|
|
|
return ['tables' => count($tables), 'rows' => $rowCount];
|
|
}
|
|
}
|
|
|