From 95d6f72ff944873b90a0587dcab84cac60b6af59 Mon Sep 17 00:00:00 2001 From: Mousab Salah Date: Thu, 8 Oct 2026 15:23:49 +0300 Subject: [PATCH] feat: add getters to Atom\Link, Media\Content, and Media\Thumbnail These extensions only exposed setters, so their values could not be read back once built. Add getters mirroring every setter, following the convention of the other value objects. Content::isDefault() is already the setter, so its getter is getIsDefault(). The generated XML is unchanged. Refs #3 --- CHANGELOG.md | 6 ++ docs/sections/11-elements-api.md | 6 +- src/Extensions/Atom/Link.php | 30 ++++++++ src/Extensions/Media/Content.php | 73 ++++++++++++++++++++ src/Extensions/Media/Thumbnail.php | 20 ++++++ tests/Unit/Extensions/AtomLinkTest.php | 44 ++++++++++++ tests/Unit/Extensions/MediaContentTest.php | 58 ++++++++++++++++ tests/Unit/Extensions/MediaThumbnailTest.php | 27 ++++++++ 8 files changed, 261 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d262fec..4fe6b04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## Unreleased + +### Added + +- Getters on `Atom\Link`, `Media\Content`, and `Media\Thumbnail`, matching their setters. `Content::isDefault()` is the setter, so its getter is `getIsDefault()`. + ## 8.2.0 - 2026-10-06 The PHP 8.2 line of the package, with the same API and features as 8.1.0. See [UPGRADE.md](UPGRADE.md) for migrating from 1.x. diff --git a/docs/sections/11-elements-api.md b/docs/sections/11-elements-api.md index 36d6b29..e40312a 100644 --- a/docs/sections/11-elements-api.md +++ b/docs/sections/11-elements-api.md @@ -26,11 +26,11 @@ Structured elements are small `final` value objects. Each has a static `make()` | Class | Create with | Setters | | --- | --- | --- | -| `Atom\Link` | `make(string $href)`, `self(string $href)` | `rel()`, `type()`, `hreflang()`, `title()`, `length(?int)` | +| `Atom\Link` | `make(string $href)`, `self(string $href)` | `rel()`, `type()`, `hreflang()`, `title()`, `length(?int)`; getters `getHref()`, `getRel()`, `getType()`, `getHreflang()`, `getTitle()`, `getLength()` | | `Content\Encoded` | `make(string $content)` | Getter: `getContent()` | | `DublinCore\Creator` | `make(string $name)` | Getter: `getName()` | -| `Media\Content` | `make(string $url)` | `fileSize()`, `type()`, `medium()`, `isDefault()`, `expression()`, `bitrate()`, `duration()`, `width()`, `height()`, `lang()`, `title(?Title)`, `description(?Description)`, `thumbnail(Thumbnail)` | -| `Media\Thumbnail` | `make(string $url)` | `width()`, `height()`, `time(?string)` | +| `Media\Content` | `make(string $url)` | `fileSize()`, `type()`, `medium()`, `isDefault()`, `expression()`, `bitrate()`, `duration()`, `width()`, `height()`, `lang()`, `title(?Title)`, `description(?Description)`, `thumbnail(Thumbnail)`; getters `getUrl()`, `getFileSize()`, `getType()`, `getMedium()`, `getIsDefault()`, `getExpression()`, `getBitrate()`, `getDuration()`, `getWidth()`, `getHeight()`, `getLang()`, `getTitle()`, `getDescription()`, `getThumbnails()` | +| `Media\Thumbnail` | `make(string $url)` | `width()`, `height()`, `time(?string)`; getters `getUrl()`, `getWidth()`, `getHeight()`, `getTime()` | | `Media\Title` | `make(string $text)` | `type(?string)`; getters `getText()`, `getType()` | | `Media\Description` | `make(string $text)` | `type(?string)`; getters `getText()`, `getType()` | diff --git a/src/Extensions/Atom/Link.php b/src/Extensions/Atom/Link.php index c0dbf11..f252947 100644 --- a/src/Extensions/Atom/Link.php +++ b/src/Extensions/Atom/Link.php @@ -108,6 +108,36 @@ public function length(?int $length): self return $this; } + public function getHref(): string + { + return $this->href; + } + + public function getRel(): ?string + { + return $this->rel; + } + + public function getType(): ?string + { + return $this->type; + } + + public function getHreflang(): ?string + { + return $this->hreflang; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function getLength(): ?int + { + return $this->length; + } + public function write(XMLWriter $writer): void { $writer->startElement($this->prefix() . ':link'); diff --git a/src/Extensions/Media/Content.php b/src/Extensions/Media/Content.php index 35b88c0..a800e52 100644 --- a/src/Extensions/Media/Content.php +++ b/src/Extensions/Media/Content.php @@ -236,6 +236,79 @@ public function thumbnail(Thumbnail $thumbnail): self return $this; } + public function getUrl(): string + { + return $this->url; + } + + public function getFileSize(): ?int + { + return $this->fileSize; + } + + public function getType(): ?string + { + return $this->type; + } + + public function getMedium(): ?string + { + return $this->medium; + } + + public function getIsDefault(): ?bool + { + return $this->isDefault; + } + + public function getExpression(): ?string + { + return $this->expression; + } + + public function getBitrate(): ?int + { + return $this->bitrate; + } + + public function getDuration(): ?int + { + return $this->duration; + } + + public function getWidth(): ?int + { + return $this->width; + } + + public function getHeight(): ?int + { + return $this->height; + } + + public function getLang(): ?string + { + return $this->lang; + } + + public function getTitle(): ?Title + { + return $this->title; + } + + public function getDescription(): ?Description + { + return $this->description; + } + + /** + * @return list + */ + public function getThumbnails(): array + { + return $this->thumbnails; + } + public function write(XMLWriter $writer): void { $writer->startElement($this->prefix() . ':content'); diff --git a/src/Extensions/Media/Thumbnail.php b/src/Extensions/Media/Thumbnail.php index 5c4b795..1d8f108 100644 --- a/src/Extensions/Media/Thumbnail.php +++ b/src/Extensions/Media/Thumbnail.php @@ -73,6 +73,26 @@ public function time(?string $time): self return $this; } + public function getUrl(): string + { + return $this->url; + } + + public function getWidth(): ?int + { + return $this->width; + } + + public function getHeight(): ?int + { + return $this->height; + } + + public function getTime(): ?string + { + return $this->time; + } + public function write(XMLWriter $writer): void { $writer->startElement($this->prefix() . ':thumbnail'); diff --git a/tests/Unit/Extensions/AtomLinkTest.php b/tests/Unit/Extensions/AtomLinkTest.php index 09d9355..811f9d0 100644 --- a/tests/Unit/Extensions/AtomLinkTest.php +++ b/tests/Unit/Extensions/AtomLinkTest.php @@ -63,6 +63,50 @@ public function testOptionalAttributesCanBeRemoved(): void $this->assertXPathCount(1, $xpath, '/root/atom:link/@*'); } + public function testGettersReturnNullByDefault(): void + { + $link = Link::make('https://example.com/rss.xml'); + + $this->assertSame('https://example.com/rss.xml', $link->getHref()); + $this->assertNull($link->getRel()); + $this->assertNull($link->getType()); + $this->assertNull($link->getHreflang()); + $this->assertNull($link->getTitle()); + $this->assertNull($link->getLength()); + } + + public function testGettersReturnTheConfiguredValues(): void + { + $link = Link::make('https://example.com/feed') + ->rel('alternate') + ->type('text/html') + ->hreflang('ar') + ->title('النسخة العربية') + ->length(1024); + + $this->assertSame('alternate', $link->getRel()); + $this->assertSame('text/html', $link->getType()); + $this->assertSame('ar', $link->getHreflang()); + $this->assertSame('النسخة العربية', $link->getTitle()); + $this->assertSame(1024, $link->getLength()); + } + + public function testSelfLinkGetters(): void + { + $link = Link::self('https://example.com/rss.xml'); + + $this->assertSame('self', $link->getRel()); + $this->assertSame('application/rss+xml', $link->getType()); + } + + public function testRemovedAttributesAreReturnedAsNull(): void + { + $link = Link::self('https://example.com/rss.xml')->rel(null)->type(''); + + $this->assertNull($link->getRel()); + $this->assertNull($link->getType()); + } + public function testRejectsEmptyHref(): void { $this->expectException(InvalidElementException::class); diff --git a/tests/Unit/Extensions/MediaContentTest.php b/tests/Unit/Extensions/MediaContentTest.php index c140ecf..b043394 100644 --- a/tests/Unit/Extensions/MediaContentTest.php +++ b/tests/Unit/Extensions/MediaContentTest.php @@ -82,6 +82,64 @@ public function testWritesNestedElements(): void ); } + public function testGettersReturnNullByDefault(): void + { + $content = Content::make('https://example.com/video.mp4'); + + $this->assertSame('https://example.com/video.mp4', $content->getUrl()); + $this->assertNull($content->getFileSize()); + $this->assertNull($content->getType()); + $this->assertNull($content->getMedium()); + $this->assertNull($content->getIsDefault()); + $this->assertNull($content->getExpression()); + $this->assertNull($content->getBitrate()); + $this->assertNull($content->getDuration()); + $this->assertNull($content->getWidth()); + $this->assertNull($content->getHeight()); + $this->assertNull($content->getLang()); + $this->assertNull($content->getTitle()); + $this->assertNull($content->getDescription()); + $this->assertSame([], $content->getThumbnails()); + } + + public function testGettersReturnTheConfiguredValues(): void + { + $title = Title::make('Launch video'); + $description = Description::make('Behind the scenes'); + $first = Thumbnail::make('https://example.com/1.jpg'); + $second = Thumbnail::make('https://example.com/2.jpg'); + + $content = Content::make('https://example.com/video.mp4') + ->fileSize(12216320) + ->type('video/mp4') + ->medium(Content::MEDIUM_VIDEO) + ->isDefault(false) + ->expression(Content::EXPRESSION_FULL) + ->bitrate(128) + ->duration(185) + ->width(1920) + ->height(1080) + ->lang('en') + ->title($title) + ->description($description) + ->thumbnail($first) + ->thumbnail($second); + + $this->assertSame(12216320, $content->getFileSize()); + $this->assertSame('video/mp4', $content->getType()); + $this->assertSame('video', $content->getMedium()); + $this->assertFalse($content->getIsDefault()); + $this->assertSame('full', $content->getExpression()); + $this->assertSame(128, $content->getBitrate()); + $this->assertSame(185, $content->getDuration()); + $this->assertSame(1920, $content->getWidth()); + $this->assertSame(1080, $content->getHeight()); + $this->assertSame('en', $content->getLang()); + $this->assertSame($title, $content->getTitle()); + $this->assertSame($description, $content->getDescription()); + $this->assertSame([$first, $second], $content->getThumbnails()); + } + public function testRejectsEmptyUrl(): void { $this->expectException(InvalidElementException::class); diff --git a/tests/Unit/Extensions/MediaThumbnailTest.php b/tests/Unit/Extensions/MediaThumbnailTest.php index 27c9c07..f2c5e24 100644 --- a/tests/Unit/Extensions/MediaThumbnailTest.php +++ b/tests/Unit/Extensions/MediaThumbnailTest.php @@ -36,6 +36,33 @@ public function testWritesAllAttributes(): void ); } + public function testGettersReturnNullByDefault(): void + { + $thumbnail = Thumbnail::make('https://example.com/image.jpg'); + + $this->assertSame('https://example.com/image.jpg', $thumbnail->getUrl()); + $this->assertNull($thumbnail->getWidth()); + $this->assertNull($thumbnail->getHeight()); + $this->assertNull($thumbnail->getTime()); + } + + public function testGettersReturnTheConfiguredValues(): void + { + $thumbnail = Thumbnail::make('https://example.com/image.jpg') + ->width(1200) + ->height(630) + ->time('12:05:01.123'); + + $this->assertSame(1200, $thumbnail->getWidth()); + $this->assertSame(630, $thumbnail->getHeight()); + $this->assertSame('12:05:01.123', $thumbnail->getTime()); + } + + public function testEmptyTimeIsReturnedAsNull(): void + { + $this->assertNull(Thumbnail::make('https://example.com/image.jpg')->time('')->getTime()); + } + public function testRejectsEmptyUrl(): void { $this->expectException(InvalidElementException::class);