query( "CREATE TABLE IF NOT EXISTS users ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, customer_number INT NOT NULL, display_name VARCHAR(255) NULL, email VARCHAR(255) NULL, phone_country_code INT NULL, phone BIGINT NULL, password VARCHAR(255) NULL, group_id INT NOT NULL DEFAULT 0, xlvask_customer_id VARCHAR(255) NULL, sms_notifications_enabled TINYINT(1) NOT NULL DEFAULT 0, email_notifications_enabled TINYINT(1) NOT NULL DEFAULT 0, wash_certificate_email VARCHAR(255) NULL, invoice_email VARCHAR(255) NULL, two_factor_enabled TINYINT(1) NOT NULL DEFAULT 0, two_factor_secret VARCHAR(255) NULL, created_at DATETIME NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted_at DATETIME NULL, KEY idx_users_customer_number (customer_number), KEY idx_users_group_id (group_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" ); } private static function ensureInvoiceEmailColumn(object $db): void { if (!self::tableExists($db, self::TABLE)) { return; } if (self::columnExists($db, self::TABLE, self::COLUMN)) { return; } $safeTable = str_replace('`', '', self::TABLE); $db->query( "ALTER TABLE `{$safeTable}` ADD COLUMN " . self::COLUMN . " VARCHAR(255) NULL AFTER wash_certificate_email" ); } private static function tableExists(object $db, string $table): bool { $safeTable = str_replace('`', '', $table); $result = $db->query("SHOW TABLES LIKE '{$safeTable}'"); return $result && (int)$result->num_rows > 0; } private static function columnExists(object $db, string $table, string $column): bool { $safeTable = str_replace('`', '', $table); $safeColumn = str_replace("'", '', $column); $result = $db->query("SHOW COLUMNS FROM `{$safeTable}` LIKE '{$safeColumn}'"); return $result && (int)$result->num_rows > 0; } }