sourceTable = $sourceTable; $this->prefixedSourceTable = $this->wpdb->prefix . 'statistics_' . $sourceTable; return $this; } /** * Execute the insert operation, supporting migration, inserts, and updates. * * @return void * @throws RuntimeException */ public function execute() { try { $this->ensureConnection(); $this->validateTableName(); $this->validateArgs(); $this->setFullTableName(); if (!empty($this->sourceTable)) { $this->transactionHandler->executeInTransaction([$this, 'migrateData']); } elseif (!empty($this->args['conditions'])) { $this->transactionHandler->executeInTransaction([$this, 'insertOrUpdateData']); } else { $this->transactionHandler->executeInTransaction([$this, 'insertData']); } } catch (\Exception $e) { Option::saveOptionGroup('migration_status_detail', [ 'status' => 'failed', 'message' => $e->getMessage() ], 'db'); throw new RuntimeException( sprintf("Failed to insert/update data in table `%s`: %s", $this->tableName, $e->getMessage()) ); } } /** * Handles inserting or updating data based on `conditions` (e.g., visitor_id). */ public function insertOrUpdateData() { $mapping = $this->args['mapping'] ?? []; $conditions = $this->args['conditions'] ?? []; if (empty($mapping) || empty($conditions)) { throw new RuntimeException("Mapping and conditions are required for updating data."); } // Construct WHERE clause from conditions $whereClauses = []; $params = []; foreach ($conditions as $column => $value) { $whereClauses[] = "`$column` = %s"; $params[] = $value; } $whereQuery = implode(' AND ', $whereClauses); // Check if a matching record exists $existsQuery = "SELECT COUNT(*) FROM {$this->fullName} WHERE $whereQuery"; $exists = $this->wpdb->get_var($this->wpdb->prepare($existsQuery, ...$params)); if ($exists > 0) { // Update existing record $result = $this->wpdb->update($this->fullName, $mapping, $conditions); if ($result === false) { throw new RuntimeException("Failed to update data: {$this->wpdb->last_error}"); } } else { // Insert new record $mergedData = array_merge($mapping, $conditions); $result = $this->wpdb->insert($this->fullName, $mergedData); if ($result === false) { throw new RuntimeException("Failed to insert data: {$this->wpdb->last_error}"); } } } /** * Migrate data operation to be executed within a transaction. * * @return void * @throws RuntimeException */ public function migrateData() { if (empty($this->sourceTable)) { throw new RuntimeException("Source table is not specified for migration."); } $mapping = $this->args['mapping'] ?? []; $distinctFields = $this->args['distinct_fields'] ?? []; $sourceTableSet = $this->args['source_table_set'] ?? []; if (empty($mapping)) { throw new RuntimeException("Mapping is required for migration."); } $batchSize = $this->args['batch_size'] ?? 50; $offset = $this->args['offset'] ?? 0; // Prepare the columns for fetching data from the source table $sourceColumns = implode(', ', array_values($mapping)); $rows = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT $sourceColumns FROM {$this->prefixedSourceTable} LIMIT %d OFFSET %d", $batchSize, $offset ), ARRAY_A ); if ($rows === null || $rows === false) { throw new RuntimeException("Failed to fetch rows: {$this->wpdb->last_error}"); } foreach ($rows as $row) { $mappedRow = []; foreach ($mapping as $targetColumn => $sourceColumn) { if (isset($row[$sourceColumn])) { $mappedRow[$targetColumn] = $row[$sourceColumn]; } } if ($this->shouldSkipDuplicate($mappedRow, $distinctFields)) { continue; } $this->performInsert($mappedRow); } } /** * Determines whether a row should be skipped based on `distinct_fields`. * * @param array $row * @param array $distinctFields * @return bool */ private function shouldSkipDuplicate(array $row, array $distinctFields): bool { if (empty($distinctFields)) { return false; } $conditions = []; foreach ($distinctFields as $field) { if (isset($row[$field])) { $conditions[] = $this->wpdb->prepare("`$field` = %s", $row[$field]); } } if (empty($conditions)) { return false; } $conditionQuery = implode(' AND ', $conditions); $exists = $this->wpdb->get_var("SELECT COUNT(*) FROM {$this->fullName} WHERE $conditionQuery"); return $exists > 0; } }