feat: add sync result value object

This commit is contained in:
Keith Solomon
2026-04-28 13:42:32 -05:00
parent 52543aab2d
commit 90cb78b712
2 changed files with 188 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
<?php
/**
* Immutable sync operation result.
*
* @package WPContentSync
*/
namespace WPContentSync\Sync;
final class SyncResult {
private bool $successful;
private int $created;
private int $updated;
private int $skipped;
private int $conflicts;
/** @var array<int, string> */
private array $errors;
/**
* @param array<int, string> $errors Error messages.
*/
private function __construct( bool $successful, int $created, int $updated, int $skipped, int $conflicts, array $errors ) {
$this->successful = $successful;
$this->created = max( 0, $created );
$this->updated = max( 0, $updated );
$this->skipped = max( 0, $skipped );
$this->conflicts = max( 0, $conflicts );
$this->errors = array_values( array_map( 'strval', $errors ) );
}
/**
* @param array<string, int> $counts Result counts.
*/
public static function success( array $counts = array() ): self {
return new self(
true,
(int) ( $counts['created'] ?? 0 ),
(int) ( $counts['updated'] ?? 0 ),
(int) ( $counts['skipped'] ?? 0 ),
(int) ( $counts['conflicts'] ?? 0 ),
array()
);
}
/**
* @param array<int, string> $errors Error messages.
*/
public static function failure( array $errors ): self {
return new self( false, 0, 0, 0, 0, $errors );
}
/**
* @param array<int, self> $results Results to merge.
*/
public static function merge( array $results ): self {
$successful = true;
$created = 0;
$updated = 0;
$skipped = 0;
$conflicts = 0;
$errors = array();
foreach ( $results as $result ) {
$successful = $successful && $result->isSuccessful();
$created += $result->created();
$updated += $result->updated();
$skipped += $result->skipped();
$conflicts += $result->conflicts();
$errors = array_merge( $errors, $result->errors() );
}
return new self( $successful, $created, $updated, $skipped, $conflicts, $errors );
}
public function isSuccessful(): bool {
return $this->successful;
}
public function created(): int {
return $this->created;
}
public function updated(): int {
return $this->updated;
}
public function skipped(): int {
return $this->skipped;
}
public function conflicts(): int {
return $this->conflicts;
}
/**
* @return array<int, string>
*/
public function errors(): array {
return $this->errors;
}
/**
* @return array<string, mixed>
*/
public function toArray(): array {
return array(
'successful' => $this->successful,
'created' => $this->created,
'updated' => $this->updated,
'skipped' => $this->skipped,
'conflicts' => $this->conflicts,
'errors' => $this->errors,
);
}
}
+72
View File
@@ -0,0 +1,72 @@
<?php
/**
* Tests for sync result summaries.
*
* @package WPContentSync
*/
namespace WPContentSync\Tests\Unit\Sync;
use PHPUnit\Framework\TestCase;
use WPContentSync\Sync\SyncResult;
class SyncResultTest extends TestCase {
public function test_it_tracks_successful_counts(): void {
$result = SyncResult::success(
array(
'created' => 2,
'updated' => 3,
'skipped' => 1,
'conflicts' => 1,
)
);
self::assertTrue( $result->isSuccessful() );
self::assertSame( 2, $result->created() );
self::assertSame( 3, $result->updated() );
self::assertSame( 1, $result->skipped() );
self::assertSame( 1, $result->conflicts() );
self::assertSame( array(), $result->errors() );
self::assertSame(
array(
'successful' => true,
'created' => 2,
'updated' => 3,
'skipped' => 1,
'conflicts' => 1,
'errors' => array(),
),
$result->toArray()
);
}
public function test_it_tracks_failed_results(): void {
$result = SyncResult::failure( array( 'posts import failed.' ) );
self::assertFalse( $result->isSuccessful() );
self::assertSame( array( 'posts import failed.' ), $result->errors() );
}
public function test_it_merges_multiple_results(): void {
$result = SyncResult::merge(
array(
SyncResult::success( array( 'created' => 1 ) ),
SyncResult::success(
array(
'updated' => 2,
'skipped' => 1,
'conflicts' => 1,
)
),
SyncResult::failure( array( 'terms import failed.' ) ),
)
);
self::assertFalse( $result->isSuccessful() );
self::assertSame( 1, $result->created() );
self::assertSame( 2, $result->updated() );
self::assertSame( 1, $result->skipped() );
self::assertSame( 1, $result->conflicts() );
self::assertSame( array( 'terms import failed.' ), $result->errors() );
}
}