'success', 'issues' => [], 'errors' => [] ]; if (get_transient(self::SCHEMA_CHECK_SUCCESS)) { return $results; } try { $tableNames = Manager::getAllTableNames(); foreach ($tableNames as $tableName) { $inspect = DatabaseFactory::table('inspect') ->setName($tableName) ->execute(); $schema = Manager::getSchemaForTable($tableName); if (!$schema) { continue; } if (!$inspect->getResult()) { $results['issues'][] = [ 'type' => 'table_missing', 'table' => $tableName, 'schema' => $schema, ]; continue; } try { // Check columns $columns = DatabaseFactory::table('inspect_columns') ->setName($tableName) ->execute() ->getResult(); $existingColumns = array_column($columns, 'Type', 'Field'); foreach ($schema['columns'] as $columnName => $definition) { if (isset($existingColumns[$columnName])) { continue; } $indexDefinition = ''; if (!empty($schema['constraints'][$columnName])) { $indexDefinition = $schema['constraints'][$columnName]; } $results['issues'][] = [ 'type' => 'missing_column', 'table' => $tableName, 'column' => $columnName, 'columnDefinition' => $definition, 'indexDefinition' => $indexDefinition ]; } } catch (\RuntimeException $e) { if (strpos($e->getMessage(), 'does not exist') !== false) { $results['errors'][] = [ 'type' => 'failed', 'table' => $tableName ]; WP_Statistics::log($e->getMessage()); continue; } WP_Statistics::log($e->getMessage()); } } if (!empty($results['errors'])) { $results['status'] = count($results['issues']) > 0 ? 'warning' : 'error'; } elseif (!empty($results['issues'])) { $results['status'] = 'warning'; } } catch (\Exception $e) { $results['status'] = 'error'; $results['errors'][] = [ 'type' => 'system_error', 'message' => $e->getMessage() ]; WP_Statistics::log($e->getMessage()); } if ($results['status'] === 'success') { set_transient(self::SCHEMA_CHECK_SUCCESS, 1, 24 * HOUR_IN_SECONDS); } return $results; } /** * Repairs any identified schema issues in the database tables. * * @param bool $forceRecheck Clear the cached schema-check transient before repairing. * @return array Repair operation results. */ public static function repair($forceRecheck = false) { self::clearCache($forceRecheck); $results = [ 'status' => 'success', 'fixed' => [], 'failed' => [] ]; try { $checkResults = self::check(); if (empty($checkResults['issues'])) { return $results; } foreach ($checkResults['issues'] as $issue) { try { if ($issue['type'] === 'missing_column') { DatabaseFactory::table('repair') ->setName($issue['table']) ->setArgs([ 'column' => $issue['column'], 'definition' => $issue['columnDefinition'], 'indexDefinition' => $issue['indexDefinition'] ]) ->execute(); DatabaseFactory::table('inspect_columns') ->setName($issue['table']) ->updateCache(); } if ($issue['type'] === 'table_missing') { TableHandler::createTable($issue['table'], $issue['schema']); DatabaseFactory::table('inspect') ->setName($issue['table']) ->updateCache(); } $results['fixed'][] = $issue; } catch (\Exception $e) { $results['failed'][] = [ 'issue' => $issue, 'type' => 'repair_failed', 'message' => $e->getMessage() ]; WP_Statistics::log($e->getMessage()); } } if (!empty($results['failed'])) { $results['status'] = 'partial'; } } catch (\Exception $e) { $results['status'] = 'error'; $results['errors'][] = [ 'type' => 'system_error', 'message' => $e->getMessage() ]; WP_Statistics::log($e->getMessage()); } return $results; } /** * Clears the cached schema check transient if forced. * * @param bool $forceRecheck Whether to forcefully clear the schema-check cache. * @return void */ private static function clearCache($forceRecheck = false) { if (!$forceRecheck) { return; } delete_transient(self::SCHEMA_CHECK_SUCCESS); } }