feat: orchestrate package imports

This commit is contained in:
Keith Solomon
2026-05-01 15:12:22 -05:00
parent 425d42e4bb
commit e9f4b17229
2 changed files with 428 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
<?php
/**
* Orchestrates content package imports.
*
* @package WPContentSync
*/
namespace WPContentSync\Sync;
use WPContentSync\Content\ContentHandlerRegistry;
use WPContentSync\Content\ContentImportException;
use WPContentSync\Logging\LoggerInterface;
use WPContentSync\Package\ContentPackage;
use WPContentSync\Settings\SettingsRepository;
final class SyncEngine {
private ContentHandlerRegistry $handlers;
private SyncStateRepository $state_repository;
private SettingsRepository $settings_repository;
private LoggerInterface $logger;
public function __construct(
ContentHandlerRegistry $handlers,
SyncStateRepository $state_repository,
SettingsRepository $settings_repository,
LoggerInterface $logger
) {
$this->handlers = $handlers;
$this->state_repository = $state_repository;
$this->settings_repository = $settings_repository;
$this->logger = $logger;
}
public function importPackage( ContentPackage $package ): SyncResult {
$operation_id = uniqid( 'wpcs_', true );
$total = $this->totalRecords( $package );
$processed = 0;
$results = array();
$context = SyncContext::forImport(
$package->source(),
$package->destination(),
$this->settings_repository->get()->conflictStrategy(),
$operation_id
);
$this->logger->info(
'Starting content package import.',
array(
'operation_id' => $operation_id,
'total' => $total,
)
);
foreach ( $this->handlers->ordered() as $handler ) {
$bucket = $handler->bucket();
$records = $this->recordsForBucket( $package, $bucket );
$this->state_repository->save( SyncOperationState::running( $operation_id, $bucket, $processed, $total ) );
try {
$results[] = $handler->importRecords( $records, $context );
} catch ( ContentImportException $exception ) {
$this->state_repository->save(
SyncOperationState::fromArray(
array(
'operation_id' => $operation_id,
'status' => 'failed',
'current_bucket' => $bucket,
'processed' => $processed,
'total' => $total,
)
)
);
$this->logger->error(
'Content package import failed.',
array(
'operation_id' => $operation_id,
'bucket' => $exception->bucket(),
'record' => $exception->record(),
'error' => $exception->getMessage(),
)
);
$results[] = SyncResult::failure( array( $exception->getMessage() ) );
return SyncResult::merge( $results );
}
$processed += count( $records );
}
$result = SyncResult::merge( $results );
$this->state_repository->save( SyncOperationState::completed( $operation_id, $processed, $total ) );
$this->logger->info(
'Completed content package import.',
array_merge(
array( 'operation_id' => $operation_id ),
$result->toArray()
)
);
return $result;
}
private function totalRecords( ContentPackage $package ): int {
$total = 0;
foreach ( $package->manifest() as $count ) {
$total += max( 0, (int) $count );
}
return $total;
}
/**
* @return array<int, array<string, mixed>>
*/
private function recordsForBucket( ContentPackage $package, string $bucket ): array {
$records = $package->records()[ $bucket ] ?? array();
if ( ! is_array( $records ) ) {
return array();
}
return array_values(
array_filter(
$records,
static function ( $record ): bool {
return is_array( $record );
}
)
);
}
}