From 5c0b22f4c4dc9b43159b22c4166e953d6205e41b Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Tue, 28 Apr 2026 13:55:09 -0500 Subject: [PATCH] feat: add content handler registry --- src/Content/ContentHandlerInterface.php | 20 +++++++ src/Content/ContentHandlerRegistry.php | 54 +++++++++++++++++++ src/Content/ContentImportException.php | 36 +++++++++++++ .../Content/ContentHandlerRegistryTest.php | 54 +++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 src/Content/ContentHandlerInterface.php create mode 100644 src/Content/ContentHandlerRegistry.php create mode 100644 src/Content/ContentImportException.php create mode 100644 tests/Unit/Content/ContentHandlerRegistryTest.php diff --git a/src/Content/ContentHandlerInterface.php b/src/Content/ContentHandlerInterface.php new file mode 100644 index 0000000..8350588 --- /dev/null +++ b/src/Content/ContentHandlerInterface.php @@ -0,0 +1,20 @@ +> $records Package records for this handler bucket. + */ + public function importRecords( array $records, SyncContext $context ): SyncResult; +} diff --git a/src/Content/ContentHandlerRegistry.php b/src/Content/ContentHandlerRegistry.php new file mode 100644 index 0000000..7b3a90f --- /dev/null +++ b/src/Content/ContentHandlerRegistry.php @@ -0,0 +1,54 @@ + */ + private array $handlers = array(); + + /** + * @param array $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 + */ + public function ordered(): array { + $ordered = array(); + + foreach ( self::PACKAGE_ORDER as $bucket ) { + if ( isset( $this->handlers[ $bucket ] ) ) { + $ordered[] = $this->handlers[ $bucket ]; + } + } + + return $ordered; + } +} diff --git a/src/Content/ContentImportException.php b/src/Content/ContentImportException.php new file mode 100644 index 0000000..76ab60e --- /dev/null +++ b/src/Content/ContentImportException.php @@ -0,0 +1,36 @@ + */ + private array $record; + + /** + * @param array $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 + */ + public function record(): array { + return $this->record; + } +} diff --git a/tests/Unit/Content/ContentHandlerRegistryTest.php b/tests/Unit/Content/ContentHandlerRegistryTest.php new file mode 100644 index 0000000..488b9b9 --- /dev/null +++ b/tests/Unit/Content/ContentHandlerRegistryTest.php @@ -0,0 +1,54 @@ +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> $records Package records. + */ + public function importRecords( array $records, SyncContext $context ): SyncResult { + return SyncResult::success( array( 'skipped' => count( $records ) ) ); + } + }; + } +}