feat: add content handler registry

This commit is contained in:
Keith Solomon
2026-04-28 13:55:09 -05:00
parent b176a37457
commit 5c0b22f4c4
4 changed files with 164 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
<?php
/**
* Content package handler boundary.
*
* @package WPContentSync
*/
namespace WPContentSync\Content;
use WPContentSync\Sync\SyncContext;
use WPContentSync\Sync\SyncResult;
interface ContentHandlerInterface {
public function bucket(): string;
/**
* @param array<int, array<string, mixed>> $records Package records for this handler bucket.
*/
public function importRecords( array $records, SyncContext $context ): SyncResult;
}
+54
View File
@@ -0,0 +1,54 @@
<?php
/**
* Ordered content handler registry.
*
* @package WPContentSync
*/
namespace WPContentSync\Content;
final class ContentHandlerRegistry {
private const PACKAGE_ORDER = array(
'custom_post_types',
'terms',
'posts',
'media',
);
/** @var array<string, ContentHandlerInterface> */
private array $handlers = array();
/**
* @param array<int, ContentHandlerInterface> $handlers Content handlers.
*/
public function __construct( array $handlers ) {
foreach ( $handlers as $handler ) {
$this->register( $handler );
}
}
private function register( ContentHandlerInterface $handler ): void {
$bucket = $handler->bucket();
if ( isset( $this->handlers[ $bucket ] ) ) {
throw new \InvalidArgumentException( sprintf( 'Handler bucket "%s" is already registered.', $bucket ) );
}
$this->handlers[ $bucket ] = $handler;
}
/**
* @return array<int, ContentHandlerInterface>
*/
public function ordered(): array {
$ordered = array();
foreach ( self::PACKAGE_ORDER as $bucket ) {
if ( isset( $this->handlers[ $bucket ] ) ) {
$ordered[] = $this->handlers[ $bucket ];
}
}
return $ordered;
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
/**
* Typed content import failure.
*
* @package WPContentSync
*/
namespace WPContentSync\Content;
final class ContentImportException extends \RuntimeException {
private string $bucket;
/** @var array<string, mixed> */
private array $record;
/**
* @param array<string, mixed> $record Content record that failed.
*/
public function __construct( string $bucket, array $record, string $message, ?\Throwable $previous = null ) {
parent::__construct( $message, 0, $previous );
$this->bucket = $bucket;
$this->record = $record;
}
public function bucket(): string {
return $this->bucket;
}
/**
* @return array<string, mixed>
*/
public function record(): array {
return $this->record;
}
}
@@ -0,0 +1,54 @@
<?php
/**
* Tests for content handler registry.
*
* @package WPContentSync
*/
namespace WPContentSync\Tests\Unit\Content;
use PHPUnit\Framework\TestCase;
use WPContentSync\Content\ContentHandlerInterface;
use WPContentSync\Content\ContentHandlerRegistry;
use WPContentSync\Sync\SyncContext;
use WPContentSync\Sync\SyncResult;
class ContentHandlerRegistryTest extends TestCase {
public function test_it_returns_handlers_in_package_order(): void {
$posts = $this->handler( 'posts' );
$terms = $this->handler( 'terms' );
$media = $this->handler( 'media' );
$registry = new ContentHandlerRegistry( array( $media, $posts, $terms ) );
self::assertSame( array( $terms, $posts, $media ), $registry->ordered() );
}
public function test_it_rejects_duplicate_buckets(): void {
$this->expectException( \InvalidArgumentException::class );
$this->expectExceptionMessage( 'Handler bucket "posts" is already registered.' );
new ContentHandlerRegistry( array( $this->handler( 'posts' ), $this->handler( 'posts' ) ) );
}
private function handler( string $bucket ): ContentHandlerInterface {
return new class( $bucket ) implements ContentHandlerInterface {
private string $bucket;
public function __construct( string $bucket ) {
$this->bucket = $bucket;
}
public function bucket(): string {
return $this->bucket;
}
/**
* @param array<int, array<string, mixed>> $records Package records.
*/
public function importRecords( array $records, SyncContext $context ): SyncResult {
return SyncResult::success( array( 'skipped' => count( $records ) ) );
}
};
}
}