'VARCHAR(255) DEFAULT NULL', 'name_ar' => 'VARCHAR(255) DEFAULT NULL', 'created_at' => 'TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP', ]; foreach ($columns as $column => $definition) { if (payment_methods_schema_sync_20260502_column_exists($pdo, 'payment_methods', $column)) { continue; } payment_methods_schema_sync_20260502_exec( $pdo, sprintf( 'ALTER TABLE `payment_methods` ADD COLUMN `%s` %s', str_replace('`', '', $column), $definition ) ); } payment_methods_schema_sync_20260502_backfill_legacy_names($pdo); payment_methods_schema_sync_20260502_seed_defaults($pdo); } function payment_methods_schema_sync_20260502_table_exists(PDO $pdo, string $table): bool { $stmt = $pdo->prepare( 'SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :table LIMIT 1' ); $stmt->execute(['table' => $table]); return (bool)$stmt->fetchColumn(); } function payment_methods_schema_sync_20260502_column_exists(PDO $pdo, string $table, string $column): bool { $stmt = $pdo->prepare( 'SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :table AND COLUMN_NAME = :column LIMIT 1' ); $stmt->execute([ 'table' => $table, 'column' => $column, ]); return (bool)$stmt->fetchColumn(); } function payment_methods_schema_sync_20260502_backfill_legacy_names(PDO $pdo): void { if (!payment_methods_schema_sync_20260502_table_exists($pdo, 'payment_methods')) { return; } $hasLegacyName = payment_methods_schema_sync_20260502_column_exists($pdo, 'payment_methods', 'name'); $hasNameEn = payment_methods_schema_sync_20260502_column_exists($pdo, 'payment_methods', 'name_en'); $hasNameAr = payment_methods_schema_sync_20260502_column_exists($pdo, 'payment_methods', 'name_ar'); if ($hasLegacyName && $hasNameEn) { $pdo->exec( "UPDATE `payment_methods` SET `name_en` = CASE WHEN `name_en` IS NULL OR TRIM(`name_en`) = '' THEN `name` ELSE `name_en` END WHERE `name` IS NOT NULL AND TRIM(`name`) <> ''" ); } if ($hasNameAr) { $sourceExpression = $hasLegacyName ? "COALESCE(NULLIF(`name_en`, ''), `name`)" : '`name_en`'; $pdo->exec( "UPDATE `payment_methods` SET `name_ar` = $sourceExpression WHERE (`name_ar` IS NULL OR TRIM(`name_ar`) = '') AND $sourceExpression IS NOT NULL AND TRIM($sourceExpression) <> ''" ); } } function payment_methods_schema_sync_20260502_seed_defaults(PDO $pdo): void { if (!payment_methods_schema_sync_20260502_table_exists($pdo, 'payment_methods')) { return; } $count = (int)$pdo->query('SELECT COUNT(*) FROM `payment_methods`')->fetchColumn(); if ($count > 0) { return; } $defaults = [ ['Cash', 'كاش'], ['Credit Card', 'بطاقة بنكية'], ['Bank Transfer', 'تحويل بنكي'], ]; $stmt = $pdo->prepare('INSERT INTO `payment_methods` (`name_en`, `name_ar`) VALUES (?, ?)'); foreach ($defaults as [$nameEn, $nameAr]) { $stmt->execute([$nameEn, $nameAr]); } } function payment_methods_schema_sync_20260502_exec(PDO $pdo, string $statement): void { try { $pdo->exec($statement); } catch (PDOException $exception) { if (payment_methods_schema_sync_20260502_is_ignorable($exception)) { return; } throw $exception; } } function payment_methods_schema_sync_20260502_is_ignorable(PDOException $exception): bool { $driverCode = isset($exception->errorInfo[1]) ? (int)$exception->errorInfo[1] : null; $message = strtolower($exception->getMessage()); $ignorableCodes = [1050, 1060, 1061, 1062, 1091, 1826]; $ignorableSnippets = [ 'already exists', 'duplicate column name', 'duplicate key name', 'duplicate entry', 'duplicate foreign key constraint name', 'duplicate key on write or update', 'errno: 121', 'check that column/key exists', ]; if ($driverCode !== null && in_array($driverCode, $ignorableCodes, true)) { return true; } foreach ($ignorableSnippets as $snippet) { if (str_contains($message, $snippet)) { return true; } } return false; } } payment_methods_schema_sync_20260502_run(); return true;