From 14d4774f85645b91cc21e38b9c8393893d4a5a26 Mon Sep 17 00:00:00 2001 From: Tomas Smetka Date: Wed, 11 Mar 2026 00:57:44 +0100 Subject: [PATCH] Support nested content, performance issue --- README.md | 61 ++++++++----- src/DTO/Content.php | 21 ++++- src/Enum/IncludeContent.php | 24 +++++ src/PoboClient.php | 37 ++++++-- tests/BlogTest.php | 53 +++++++++++ tests/CategoryTest.php | 49 +++++++++++ tests/ContentTest.php | 71 +++++++++++++++ tests/DTO/PaginatedResponseTest.php | 131 ++++++++++++++++++++++++++++ tests/Enum/IncludeContentTest.php | 50 +++++++++++ tests/PoboClientTest.php | 116 ++++++++++++++++++++++++ tests/ProductTest.php | 55 ++++++++++++ 11 files changed, 638 insertions(+), 30 deletions(-) create mode 100644 src/Enum/IncludeContent.php create mode 100644 tests/Enum/IncludeContentTest.php diff --git a/README.md b/README.md index 0ab487a..24edae6 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,11 @@ $response = $client->getProducts(lastUpdateFrom: $since); // Filter only edited products $response = $client->getProducts(isEdited: true); + +// Include optional content (marketplace HTML, raw widget JSON) +use Pobo\Sdk\Enum\IncludeContent; + +$response = $client->getProducts(include: [IncludeContent::MARKETPLACE, IncludeContent::NESTED]); ``` ### Export Categories @@ -288,24 +293,34 @@ foreach ($client->iterateBlogs() as $blog) { } ``` -## Content (HTML/Marketplace) +## Content (HTML/Marketplace/Nested) -Products, categories, and blogs include a `content` field with generated HTML content for web and marketplace: +By default, only `content.html` is returned. Use the `include` parameter to request additional content: + +| Value | Description | +|---------------|----------------------------------------------| +| `marketplace` | HTML content for marketplace (no custom CSS) | +| `nested` | Raw widget JSON from widget tables | ```php +use Pobo\Sdk\Enum\IncludeContent; use Pobo\Sdk\Enum\Language; -foreach ($client->iterateProducts() as $product) { +// Include marketplace and nested content +foreach ($client->iterateProducts(include: [IncludeContent::MARKETPLACE, IncludeContent::NESTED]) as $product) { if ($product->content !== null) { - // Get HTML content for web + // Get HTML content for web (always included) $htmlCs = $product->content->getHtml(Language::CS); $htmlSk = $product->content->getHtml(Language::SK); $htmlEn = $product->content->getHtml(Language::EN); - // Get content for marketplace + // Get content for marketplace (requires include: ['marketplace']) $marketplaceCs = $product->content->getMarketplace(Language::CS); $marketplaceSk = $product->content->getMarketplace(Language::SK); + // Get raw widget JSON (requires include: ['nested']) + $nested = $product->content->getNested(); + // Get default content $htmlDefault = $product->content->getHtmlDefault(); $marketplaceDefault = $product->content->getMarketplaceDefault(); @@ -313,16 +328,18 @@ foreach ($client->iterateProducts() as $product) { } // Same for categories -foreach ($client->iterateCategories() as $category) { +foreach ($client->iterateCategories(include: [IncludeContent::NESTED]) as $category) { if ($category->content !== null) { echo $category->content->getHtml(Language::CS); + $nested = $category->content->getNested(); } } // Same for blogs -foreach ($client->iterateBlogs() as $blog) { +foreach ($client->iterateBlogs(include: [IncludeContent::MARKETPLACE]) as $blog) { if ($blog->content !== null) { echo $blog->content->getHtml(Language::CS); + echo $blog->content->getMarketplace(Language::CS); } } ``` @@ -426,21 +443,21 @@ $name->toArray(); // ['default' => '...', 'cs' => '...', ...] ## API Methods -| Method | Description | -|----------------------------------------------------------------------------------------|----------------------------------| -| `importProducts(array $products)` | Bulk import products (max 100) | -| `importCategories(array $categories)` | Bulk import categories (max 100) | -| `importParameters(array $parameters)` | Bulk import parameters (max 100) | -| `importBlogs(array $blogs)` | Bulk import blogs (max 100) | -| `deleteProducts(array $ids)` | Bulk delete products (max 100) | -| `deleteCategories(array $ids)` | Bulk delete categories (max 100) | -| `deleteBlogs(array $ids)` | Bulk delete blogs (max 100) | -| `getProducts(?int $page, ?int $perPage, ?DateTime $lastUpdateFrom, ?bool $isEdited)` | Get products page | -| `getCategories(?int $page, ?int $perPage, ?DateTime $lastUpdateFrom, ?bool $isEdited)` | Get categories page | -| `getBlogs(?int $page, ?int $perPage, ?DateTime $lastUpdateFrom, ?bool $isEdited)` | Get blogs page | -| `iterateProducts(?DateTime $lastUpdateFrom, ?bool $isEdited)` | Iterate all products | -| `iterateCategories(?DateTime $lastUpdateFrom, ?bool $isEdited)` | Iterate all categories | -| `iterateBlogs(?DateTime $lastUpdateFrom, ?bool $isEdited)` | Iterate all blogs | +| Method | Description | +|---------------------------------------------------------------------------------------------------------|----------------------------------| +| `importProducts(array $products)` | Bulk import products (max 100) | +| `importCategories(array $categories)` | Bulk import categories (max 100) | +| `importParameters(array $parameters)` | Bulk import parameters (max 100) | +| `importBlogs(array $blogs)` | Bulk import blogs (max 100) | +| `deleteProducts(array $ids)` | Bulk delete products (max 100) | +| `deleteCategories(array $ids)` | Bulk delete categories (max 100) | +| `deleteBlogs(array $ids)` | Bulk delete blogs (max 100) | +| `getProducts(?int $page, ?int $perPage, ?DateTime $lastUpdateFrom, ?bool $isEdited, ?array $include)` | Get products page | +| `getCategories(?int $page, ?int $perPage, ?DateTime $lastUpdateFrom, ?bool $isEdited, ?array $include)` | Get categories page | +| `getBlogs(?int $page, ?int $perPage, ?DateTime $lastUpdateFrom, ?bool $isEdited, ?array $include)` | Get blogs page | +| `iterateProducts(?DateTime $lastUpdateFrom, ?bool $isEdited, ?array $include)` | Iterate all products | +| `iterateCategories(?DateTime $lastUpdateFrom, ?bool $isEdited, ?array $include)` | Iterate all categories | +| `iterateBlogs(?DateTime $lastUpdateFrom, ?bool $isEdited, ?array $include)` | Iterate all blogs | ## Limits diff --git a/src/DTO/Content.php b/src/DTO/Content.php index bfec4d5..4874e46 100644 --- a/src/DTO/Content.php +++ b/src/DTO/Content.php @@ -11,10 +11,12 @@ final class Content /** * @param array $html * @param array $marketplace + * @param array> $nested */ public function __construct( public readonly array $html = [], public readonly array $marketplace = [], + public readonly array $nested = [], ) { } @@ -39,14 +41,28 @@ public function getMarketplaceDefault(): ?string } /** - * @return array> + * @return array> + */ + public function getNested(): array + { + return $this->nested; + } + + /** + * @return array */ public function toArray(): array { - return [ + $result = [ 'html' => $this->html, 'marketplace' => $this->marketplace, ]; + + if ($this->nested !== []) { + $result['nested'] = $this->nested; + } + + return $result; } /** @@ -57,6 +73,7 @@ public static function fromArray(array $data): self return new self( html: $data['html'] ?? [], marketplace: $data['marketplace'] ?? [], + nested: $data['nested'] ?? [], ); } } diff --git a/src/Enum/IncludeContent.php b/src/Enum/IncludeContent.php new file mode 100644 index 0000000..2638716 --- /dev/null +++ b/src/Enum/IncludeContent.php @@ -0,0 +1,24 @@ + + */ + public static function values(): array + { + return array_column(self::cases(), 'value'); + } + + public static function isValid(string $value): bool + { + return in_array($value, self::values(), true); + } +} diff --git a/src/PoboClient.php b/src/PoboClient.php index 446daf8..5206be6 100644 --- a/src/PoboClient.php +++ b/src/PoboClient.php @@ -11,6 +11,7 @@ use Pobo\Sdk\DTO\PaginatedResponse; use Pobo\Sdk\DTO\Parameter; use Pobo\Sdk\DTO\Product; +use Pobo\Sdk\Enum\IncludeContent; use Pobo\Sdk\Exception\ApiException; use Pobo\Sdk\Exception\ValidationException; @@ -100,6 +101,7 @@ public function importBlogs(array $blogs): ImportResult } /** + * @param array|null $include Optional content to include: IncludeContent::MARKETPLACE, IncludeContent::NESTED * @throws ApiException */ public function getProducts( @@ -107,13 +109,15 @@ public function getProducts( ?int $perPage = null, ?\DateTimeInterface $lastUpdateFrom = null, ?bool $isEdited = null, + ?array $include = null, ): PaginatedResponse { - $query = $this->buildQueryParams($page, $perPage, $lastUpdateFrom, $isEdited); + $query = $this->buildQueryParams($page, $perPage, $lastUpdateFrom, $isEdited, $include); $response = $this->request('GET', '/api/v2/rest/products' . $query); return PaginatedResponse::fromArray($response, Product::class); } /** + * @param array|null $include Optional content to include: IncludeContent::MARKETPLACE, IncludeContent::NESTED * @throws ApiException */ public function getCategories( @@ -121,13 +125,15 @@ public function getCategories( ?int $perPage = null, ?\DateTimeInterface $lastUpdateFrom = null, ?bool $isEdited = null, + ?array $include = null, ): PaginatedResponse { - $query = $this->buildQueryParams($page, $perPage, $lastUpdateFrom, $isEdited); + $query = $this->buildQueryParams($page, $perPage, $lastUpdateFrom, $isEdited, $include); $response = $this->request('GET', '/api/v2/rest/categories' . $query); return PaginatedResponse::fromArray($response, Category::class); } /** + * @param array|null $include Optional content to include: IncludeContent::MARKETPLACE, IncludeContent::NESTED * @throws ApiException */ public function getBlogs( @@ -135,8 +141,9 @@ public function getBlogs( ?int $perPage = null, ?\DateTimeInterface $lastUpdateFrom = null, ?bool $isEdited = null, + ?array $include = null, ): PaginatedResponse { - $query = $this->buildQueryParams($page, $perPage, $lastUpdateFrom, $isEdited); + $query = $this->buildQueryParams($page, $perPage, $lastUpdateFrom, $isEdited, $include); $response = $this->request('GET', '/api/v2/rest/blogs' . $query); return PaginatedResponse::fromArray($response, Blog::class); } @@ -187,17 +194,19 @@ public function deleteBlogs(array $ids): DeleteResult } /** + * @param array|null $include Optional content to include: IncludeContent::MARKETPLACE, IncludeContent::NESTED * @return \Generator * @throws ApiException */ public function iterateProducts( ?\DateTimeInterface $lastUpdateFrom = null, ?bool $isEdited = null, + ?array $include = null, ): \Generator { $page = 1; do { - $response = $this->getProducts($page, self::MAX_BULK_ITEMS, $lastUpdateFrom, $isEdited); + $response = $this->getProducts($page, self::MAX_BULK_ITEMS, $lastUpdateFrom, $isEdited, $include); foreach ($response->data as $product) { yield $product; @@ -208,17 +217,19 @@ public function iterateProducts( } /** + * @param array|null $include Optional content to include: IncludeContent::MARKETPLACE, IncludeContent::NESTED * @return \Generator * @throws ApiException */ public function iterateCategories( ?\DateTimeInterface $lastUpdateFrom = null, ?bool $isEdited = null, + ?array $include = null, ): \Generator { $page = 1; do { - $response = $this->getCategories($page, self::MAX_BULK_ITEMS, $lastUpdateFrom, $isEdited); + $response = $this->getCategories($page, self::MAX_BULK_ITEMS, $lastUpdateFrom, $isEdited, $include); foreach ($response->data as $category) { yield $category; @@ -229,17 +240,19 @@ public function iterateCategories( } /** + * @param array|null $include Optional content to include: IncludeContent::MARKETPLACE, IncludeContent::NESTED * @return \Generator * @throws ApiException */ public function iterateBlogs( ?\DateTimeInterface $lastUpdateFrom = null, ?bool $isEdited = null, + ?array $include = null, ): \Generator { $page = 1; do { - $response = $this->getBlogs($page, self::MAX_BULK_ITEMS, $lastUpdateFrom, $isEdited); + $response = $this->getBlogs($page, self::MAX_BULK_ITEMS, $lastUpdateFrom, $isEdited, $include); foreach ($response->data as $blog) { yield $blog; @@ -264,11 +277,15 @@ private function validateBulkSize(array $items): void } } + /** + * @param array|null $include + */ private function buildQueryParams( ?int $page, ?int $perPage, ?\DateTimeInterface $lastUpdateFrom, ?bool $isEdited, + ?array $include = null, ): string { $params = []; @@ -288,6 +305,14 @@ private function buildQueryParams( $params['is_edited'] = $isEdited === true ? 'true' : 'false'; } + if ($include !== null && $include !== []) { + $values = array_map( + fn(IncludeContent|string $item) => $item instanceof IncludeContent ? $item->value : $item, + $include, + ); + $params['include'] = implode(',', $values); + } + return $params === [] ? '' : sprintf('?%s', http_build_query($params)); } diff --git a/tests/BlogTest.php b/tests/BlogTest.php index 3b76b5c..b899c3a 100644 --- a/tests/BlogTest.php +++ b/tests/BlogTest.php @@ -134,6 +134,59 @@ public function testBlogFromArrayWithContent(): void $this->assertSame('
Czech Marketplace
', $blog->content->getMarketplace(Language::CS)); } + public function testBlogFromArrayWithNestedContent(): void + { + $nested = [ + [['id' => 3, 'class' => 'text', 'tag' => 'p', 'children' => []]], + ]; + + $data = [ + 'id' => 'BLOG-NESTED', + 'is_visible' => true, + 'name' => ['default' => 'Blog with nested'], + 'url' => ['default' => 'https://example.com/blog'], + 'content' => [ + 'html' => [ + 'default' => '
Default HTML
', + ], + 'marketplace' => [ + 'default' => '
Default Marketplace
', + ], + 'nested' => $nested, + ], + ]; + + $blog = Blog::fromArray($data); + + $this->assertInstanceOf(Content::class, $blog->content); + $this->assertSame($nested, $blog->content->getNested()); + $this->assertCount(1, $blog->content->nested); + $this->assertSame('
Default HTML
', $blog->content->getHtmlDefault()); + $this->assertSame('
Default Marketplace
', $blog->content->getMarketplaceDefault()); + } + + public function testBlogFromArrayWithContentOnlyHtml(): void + { + $data = [ + 'id' => 'BLOG-HTML', + 'is_visible' => true, + 'name' => ['default' => 'Blog HTML only'], + 'url' => ['default' => 'https://example.com/blog'], + 'content' => [ + 'html' => [ + 'default' => '
HTML
', + ], + ], + ]; + + $blog = Blog::fromArray($data); + + $this->assertInstanceOf(Content::class, $blog->content); + $this->assertSame('
HTML
', $blog->content->getHtmlDefault()); + $this->assertSame([], $blog->content->marketplace); + $this->assertSame([], $blog->content->nested); + } + public function testBlogFromArrayWithMinimalData(): void { $data = [ diff --git a/tests/CategoryTest.php b/tests/CategoryTest.php index fd86feb..f6e5f5d 100644 --- a/tests/CategoryTest.php +++ b/tests/CategoryTest.php @@ -52,6 +52,55 @@ public function testCategoryFromArrayWithContent(): void $this->assertFalse($category->isLoaded); } + public function testCategoryFromArrayWithNestedContent(): void + { + $nested = [ + [['id' => 1, 'class' => 'empty', 'tag' => 'div', 'children' => []]], + ]; + + $data = [ + 'id' => 'CAT-003', + 'is_visible' => true, + 'name' => ['default' => 'Category with nested'], + 'url' => ['default' => 'https://example.com/category'], + 'content' => [ + 'html' => [ + 'default' => '
Default HTML
', + ], + 'nested' => $nested, + ], + ]; + + $category = Category::fromArray($data); + + $this->assertInstanceOf(Content::class, $category->content); + $this->assertSame($nested, $category->content->getNested()); + $this->assertCount(1, $category->content->nested); + $this->assertSame([], $category->content->marketplace); + } + + public function testCategoryFromArrayWithContentOnlyHtml(): void + { + $data = [ + 'id' => 'CAT-004', + 'is_visible' => true, + 'name' => ['default' => 'Category HTML only'], + 'url' => ['default' => 'https://example.com/category'], + 'content' => [ + 'html' => [ + 'default' => '
HTML
', + ], + ], + ]; + + $category = Category::fromArray($data); + + $this->assertInstanceOf(Content::class, $category->content); + $this->assertSame('
HTML
', $category->content->getHtmlDefault()); + $this->assertSame([], $category->content->marketplace); + $this->assertSame([], $category->content->nested); + } + public function testCategoryFromArrayWithoutContent(): void { $data = [ diff --git a/tests/ContentTest.php b/tests/ContentTest.php index f1ddb23..91a3f9b 100644 --- a/tests/ContentTest.php +++ b/tests/ContentTest.php @@ -105,6 +105,33 @@ public function testGetMarketplaceDefaultFallsBackToCs(): void $this->assertSame('
Czech Marketplace
', $content->getMarketplaceDefault()); } + public function testCreateContentWithNested(): void + { + $nested = [ + [['id' => 2, 'class' => 'empty', 'tag' => 'div', 'children' => []]], + [['id' => 5, 'class' => 'text', 'tag' => 'p', 'children' => []]], + ]; + + $content = Content::fromArray([ + 'html' => ['cs' => '
Czech
'], + 'marketplace' => [], + 'nested' => $nested, + ]); + + $this->assertSame($nested, $content->getNested()); + $this->assertCount(2, $content->nested); + } + + public function testNestedIsEmptyByDefault(): void + { + $content = Content::fromArray([ + 'html' => ['cs' => '
Czech
'], + ]); + + $this->assertSame([], $content->getNested()); + $this->assertSame([], $content->nested); + } + public function testToArray(): void { $content = new Content( @@ -116,21 +143,64 @@ public function testToArray(): void $this->assertArrayHasKey('html', $array); $this->assertArrayHasKey('marketplace', $array); + $this->assertArrayNotHasKey('nested', $array); $this->assertSame('
Czech
', $array['html']['cs']); $this->assertSame('
English
', $array['html']['en']); $this->assertSame('
Czech MP
', $array['marketplace']['cs']); } + public function testToArrayWithNested(): void + { + $nested = [[['id' => 1, 'class' => 'empty', 'tag' => 'div', 'children' => []]]]; + + $content = new Content( + html: ['cs' => '
Czech
'], + marketplace: [], + nested: $nested, + ); + + $array = $content->toArray(); + + $this->assertArrayHasKey('nested', $array); + $this->assertSame($nested, $array['nested']); + } + public function testEmptyContent(): void { $content = Content::fromArray([]); $this->assertSame([], $content->html); $this->assertSame([], $content->marketplace); + $this->assertSame([], $content->nested); $this->assertNull($content->getHtmlDefault()); $this->assertNull($content->getMarketplaceDefault()); } + public function testFromArrayToArrayRoundtrip(): void + { + $nested = [[['id' => 2, 'class' => 'empty', 'tag' => 'div', 'children' => []]]]; + + $data = [ + 'html' => [ + 'default' => '
Default
', + 'cs' => '
Czech
', + 'sk' => '
Slovak
', + ], + 'marketplace' => [ + 'default' => '
Default MP
', + 'cs' => '
Czech MP
', + ], + 'nested' => $nested, + ]; + + $content = Content::fromArray($data); + $array = $content->toArray(); + + $this->assertSame($data['html'], $array['html']); + $this->assertSame($data['marketplace'], $array['marketplace']); + $this->assertSame($data['nested'], $array['nested']); + } + public function testContentIsReadonly(): void { $content = new Content( @@ -140,5 +210,6 @@ public function testContentIsReadonly(): void $this->assertSame(['cs' => '
Test
'], $content->html); $this->assertSame(['cs' => '
Test MP
'], $content->marketplace); + $this->assertSame([], $content->nested); } } diff --git a/tests/DTO/PaginatedResponseTest.php b/tests/DTO/PaginatedResponseTest.php index f6df4fa..0ded838 100644 --- a/tests/DTO/PaginatedResponseTest.php +++ b/tests/DTO/PaginatedResponseTest.php @@ -5,6 +5,8 @@ namespace Pobo\Sdk\Tests\DTO; use PHPUnit\Framework\TestCase; +use Pobo\Sdk\DTO\Category; +use Pobo\Sdk\DTO\Blog; use Pobo\Sdk\DTO\PaginatedResponse; use Pobo\Sdk\DTO\Product; @@ -99,4 +101,133 @@ public function testFromArrayWithDefaults(): void $this->assertSame(100, $response->perPage); $this->assertSame(0, $response->total); } + + public function testFromArrayWithNestedContent(): void + { + $nested = [[['id' => 2, 'class' => 'empty', 'tag' => 'div', 'children' => []]]]; + + $data = [ + 'data' => [ + [ + 'id' => 'PROD-001', + 'is_visible' => true, + 'name' => ['default' => 'Product 1'], + 'url' => ['default' => 'https://example.com/1'], + 'content' => [ + 'html' => ['default' => '
HTML
'], + 'marketplace' => ['default' => '
MP
'], + 'nested' => $nested, + ], + ], + ], + 'meta' => [ + 'current_page' => 1, + 'per_page' => 100, + 'total' => 1, + ], + ]; + + $response = PaginatedResponse::fromArray($data, Product::class); + + $this->assertCount(1, $response->data); + $product = $response->data[0]; + $this->assertNotNull($product->content); + $this->assertSame('
HTML
', $product->content->getHtmlDefault()); + $this->assertSame('
MP
', $product->content->getMarketplaceDefault()); + $this->assertSame($nested, $product->content->getNested()); + } + + public function testFromArrayWithContentOnlyHtml(): void + { + $data = [ + 'data' => [ + [ + 'id' => 'PROD-002', + 'is_visible' => true, + 'name' => ['default' => 'Product 2'], + 'url' => ['default' => 'https://example.com/2'], + 'content' => [ + 'html' => ['default' => '
HTML only
'], + ], + ], + ], + 'meta' => [ + 'current_page' => 1, + 'per_page' => 100, + 'total' => 1, + ], + ]; + + $response = PaginatedResponse::fromArray($data, Product::class); + + $product = $response->data[0]; + $this->assertNotNull($product->content); + $this->assertSame('
HTML only
', $product->content->getHtmlDefault()); + $this->assertSame([], $product->content->marketplace); + $this->assertSame([], $product->content->nested); + } + + public function testFromArrayWithCategoryEntity(): void + { + $data = [ + 'data' => [ + [ + 'id' => 'CAT-001', + 'is_visible' => true, + 'name' => ['default' => 'Category 1'], + 'url' => ['default' => 'https://example.com/cat'], + 'content' => [ + 'html' => ['default' => '
Cat HTML
'], + 'nested' => [[['id' => 1, 'tag' => 'div']]], + ], + ], + ], + 'meta' => [ + 'current_page' => 1, + 'per_page' => 100, + 'total' => 1, + ], + ]; + + $response = PaginatedResponse::fromArray($data, Category::class); + + $this->assertCount(1, $response->data); + $this->assertInstanceOf(Category::class, $response->data[0]); + $this->assertNotNull($response->data[0]->content); + $this->assertCount(1, $response->data[0]->content->nested); + } + + public function testFromArrayWithBlogEntity(): void + { + $data = [ + 'data' => [ + [ + 'id' => 'BLOG-001', + 'is_visible' => true, + 'name' => ['default' => 'Blog 1'], + 'url' => ['default' => 'https://example.com/blog'], + 'content' => [ + 'html' => ['default' => '
Blog HTML
'], + 'marketplace' => ['default' => '
Blog MP
'], + 'nested' => [[['id' => 1, 'tag' => 'p']]], + ], + ], + ], + 'meta' => [ + 'current_page' => 1, + 'per_page' => 100, + 'total' => 1, + ], + ]; + + $response = PaginatedResponse::fromArray($data, Blog::class); + + $this->assertCount(1, $response->data); + $this->assertInstanceOf(Blog::class, $response->data[0]); + $blog = $response->data[0]; + $this->assertNotNull($blog->content); + $this->assertSame('
Blog HTML
', $blog->content->getHtmlDefault()); + $this->assertSame('
Blog MP
', $blog->content->getMarketplaceDefault()); + $this->assertCount(1, $blog->content->nested); + } } diff --git a/tests/Enum/IncludeContentTest.php b/tests/Enum/IncludeContentTest.php new file mode 100644 index 0000000..df7e5b7 --- /dev/null +++ b/tests/Enum/IncludeContentTest.php @@ -0,0 +1,50 @@ +assertSame('marketplace', IncludeContent::MARKETPLACE->value); + $this->assertSame('nested', IncludeContent::NESTED->value); + } + + public function testValues(): void + { + $values = IncludeContent::values(); + + $this->assertContains('marketplace', $values); + $this->assertContains('nested', $values); + $this->assertCount(2, $values); + } + + public function testIsValidReturnsTrue(): void + { + $this->assertTrue(IncludeContent::isValid('marketplace')); + $this->assertTrue(IncludeContent::isValid('nested')); + } + + public function testIsValidReturnsFalse(): void + { + $this->assertFalse(IncludeContent::isValid('html')); + $this->assertFalse(IncludeContent::isValid('')); + $this->assertFalse(IncludeContent::isValid('invalid')); + $this->assertFalse(IncludeContent::isValid('MARKETPLACE')); + $this->assertFalse(IncludeContent::isValid('NESTED')); + } + + public function testCanBeUsedInArray(): void + { + $include = [IncludeContent::MARKETPLACE, IncludeContent::NESTED]; + + $values = array_map(fn(IncludeContent $item) => $item->value, $include); + + $this->assertSame(['marketplace', 'nested'], $values); + } +} diff --git a/tests/PoboClientTest.php b/tests/PoboClientTest.php index 49f02f4..efb0f76 100644 --- a/tests/PoboClientTest.php +++ b/tests/PoboClientTest.php @@ -12,6 +12,7 @@ use Pobo\Sdk\DTO\Parameter; use Pobo\Sdk\DTO\ParameterValue; use Pobo\Sdk\DTO\Product; +use Pobo\Sdk\Enum\IncludeContent; use Pobo\Sdk\Exception\ValidationException; use Pobo\Sdk\PoboClient; @@ -327,4 +328,119 @@ public function testDeleteResultFromArray(): void $this->assertSame(1, $result->skipped); $this->assertTrue($result->hasErrors()); } + + public function testBuildQueryParamsWithIncludeEnum(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + null, + null, + null, + null, + [IncludeContent::MARKETPLACE, IncludeContent::NESTED], + ); + + $this->assertSame('?include=marketplace%2Cnested', $query); + } + + public function testBuildQueryParamsWithIncludeString(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + null, + null, + null, + null, + ['marketplace', 'nested'], + ); + + $this->assertSame('?include=marketplace%2Cnested', $query); + } + + public function testBuildQueryParamsWithIncludeSingleValue(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + null, + null, + null, + null, + [IncludeContent::NESTED], + ); + + $this->assertSame('?include=nested', $query); + } + + public function testBuildQueryParamsWithIncludeNullReturnsEmpty(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + null, + null, + null, + null, + null, + ); + + $this->assertSame('', $query); + } + + public function testBuildQueryParamsWithIncludeEmptyArrayReturnsEmpty(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + null, + null, + null, + null, + [], + ); + + $this->assertSame('', $query); + } + + public function testBuildQueryParamsWithIncludeMixedWithOtherParam(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + 1, + 50, + null, + true, + [IncludeContent::MARKETPLACE], + ); + + $this->assertStringContainsString('page=1', $query); + $this->assertStringContainsString('per_page=50', $query); + $this->assertStringContainsString('is_edited=true', $query); + $this->assertStringContainsString('include=marketplace', $query); + } + + public function testBuildQueryParamsWithMixedEnumAndString(): void + { + $method = new \ReflectionMethod(PoboClient::class, 'buildQueryParams'); + + $query = $method->invoke( + $this->client, + null, + null, + null, + null, + [IncludeContent::MARKETPLACE, 'nested'], + ); + + $this->assertSame('?include=marketplace%2Cnested', $query); + } } diff --git a/tests/ProductTest.php b/tests/ProductTest.php index 0112a85..cd1dd7f 100644 --- a/tests/ProductTest.php +++ b/tests/ProductTest.php @@ -54,6 +54,61 @@ public function testProductFromArrayWithContent(): void $this->assertSame('
Czech Marketplace
', $product->content->getMarketplace(Language::CS)); } + public function testProductFromArrayWithNestedContent(): void + { + $nested = [ + [['id' => 2, 'class' => 'empty', 'tag' => 'div', 'children' => []]], + [['id' => 5, 'class' => 'text', 'tag' => 'p', 'children' => []]], + ]; + + $data = [ + 'id' => 'PROD-003', + 'is_visible' => true, + 'name' => ['default' => 'Product with nested'], + 'url' => ['default' => 'https://example.com/product'], + 'content' => [ + 'html' => [ + 'default' => '
Default HTML
', + 'cs' => '
Czech HTML
', + ], + 'marketplace' => [ + 'default' => '
Default Marketplace
', + ], + 'nested' => $nested, + ], + ]; + + $product = Product::fromArray($data); + + $this->assertInstanceOf(Content::class, $product->content); + $this->assertSame($nested, $product->content->getNested()); + $this->assertCount(2, $product->content->nested); + $this->assertSame('
Czech HTML
', $product->content->getHtml(Language::CS)); + $this->assertSame('
Default Marketplace
', $product->content->getMarketplaceDefault()); + } + + public function testProductFromArrayWithContentOnlyHtml(): void + { + $data = [ + 'id' => 'PROD-004', + 'is_visible' => true, + 'name' => ['default' => 'Product HTML only'], + 'url' => ['default' => 'https://example.com/product'], + 'content' => [ + 'html' => [ + 'default' => '
HTML
', + ], + ], + ]; + + $product = Product::fromArray($data); + + $this->assertInstanceOf(Content::class, $product->content); + $this->assertSame('
HTML
', $product->content->getHtmlDefault()); + $this->assertSame([], $product->content->marketplace); + $this->assertSame([], $product->content->nested); + } + public function testProductFromArrayWithoutContent(): void { $data = [