0 && microtime(true) - $startedAt >= $timeLimit) { break; } $task = $this->claimNext(); if ($task === null) { break; } $this->processTask($task); $processed++; } return $processed; } /** @return array|null */ private function claimNext(): ?array { $connection = $this->resourceConnection->getConnection(); $table = $this->resourceConnection->getTableName(self::TABLE_NAME); while (true) { $queueId = (int)$connection->fetchOne( $connection->select()->from($table, 'queue_id') ->where('status = ?', 'pending') ->order('queue_id ASC') ->limit(1) ); if ($queueId <= 0) { return null; } $affected = $connection->update( $table, [ 'status' => 'processing', 'attempts' => new Expression('attempts + 1'), 'started_at' => new Expression('CURRENT_TIMESTAMP'), 'finished_at' => null, 'error_message' => null, ], ['queue_id = ?' => $queueId, 'status = ?' => 'pending'] ); if ($affected === 1) { $task = $connection->fetchRow( $connection->select()->from($table)->where('queue_id = ?', $queueId) ); return is_array($task) ? $task : null; } } } /** @param array $task */ private function processTask(array $task): void { $queueId = (int)$task['queue_id']; $provider = (string)$task['provider']; $entityType = (string)$task['entity_type']; $entityId = (int)$task['entity_id']; $sourceStoreId = (int)$task['source_store_id']; $targetStoreId = (int)$task['target_store_id']; $sourceLanguage = ''; $targetLanguage = ''; $providerFields = []; try { $entity = $this->entityPool->get($entityType); foreach ($entity->getFields($entityId, $sourceStoreId, $targetStoreId) as $field) { $value = (string)($field['source_value'] ?? ''); if ($value === '' || empty($field['code'])) { continue; } $providerFields[(string)$field['code']] = [ 'value' => $value, 'is_html' => !empty($field['is_html']), ]; } $sourceLanguage = $this->localeResolver->getLanguageCode($sourceStoreId, $provider, false); $targetLanguage = $this->localeResolver->getLanguageCode($targetStoreId, $provider, true); if ($providerFields === []) { $translations = []; } elseif ($sourceLanguage !== '' && $sourceLanguage === $targetLanguage) { $translations = $this->copyValues($providerFields); } else { $translations = $this->providerPool->get($provider)->translate( $providerFields, $sourceLanguage, $targetLanguage ); } $entity->apply($entityId, $targetStoreId, $translations); $this->safeLogSuccess( $provider, $entityType, $entityId, $sourceStoreId, $targetStoreId, $sourceLanguage, $targetLanguage, $providerFields, $translations ); $this->finish($queueId, 'success', null); } catch (\Throwable $exception) { $this->safeLogFailure( $provider, $entityType, $entityId, $sourceStoreId, $targetStoreId, $sourceLanguage, $targetLanguage, $providerFields, $exception->getMessage() ); $this->finish($queueId, 'failed', $exception->getMessage()); } } /** @param array $fields @return array */ private function copyValues(array $fields): array { $values = []; foreach ($fields as $code => $field) { $values[$code] = (string)($field['value'] ?? ''); } return $values; } private function finish(int $queueId, string $status, ?string $error): void { $connection = $this->resourceConnection->getConnection(); $connection->update( $this->resourceConnection->getTableName(self::TABLE_NAME), [ 'status' => $status, 'error_message' => $error, 'finished_at' => new Expression('CURRENT_TIMESTAMP'), ], ['queue_id = ?' => $queueId] ); } private function safeLogSuccess( string $provider, string $entityType, int $entityId, int $sourceStoreId, int $targetStoreId, string $sourceLanguage, string $targetLanguage, array $fields, array $translations ): void { try { $this->translationLogger->logSuccess( $provider, $entityType, $entityId, $sourceStoreId, $targetStoreId, $sourceLanguage, $targetLanguage, $fields, $translations, $sourceLanguage === $targetLanguage ? 'copied' : 'success' ); } catch (\Throwable) { } } private function safeLogFailure( string $provider, string $entityType, int $entityId, int $sourceStoreId, int $targetStoreId, string $sourceLanguage, string $targetLanguage, array $fields, string $error ): void { try { $this->translationLogger->logFailure( $provider, $entityType, $entityId, $sourceStoreId, $targetStoreId, $sourceLanguage, $targetLanguage, $fields, $error ); } catch (\Throwable) { } } }