Skip to content

Commit 4744a2f

Browse files
authored
feat(type): Introduce RichText value object (#46)
1 parent 27215f4 commit 4744a2f

File tree

5 files changed

+229
-0
lines changed

5 files changed

+229
-0
lines changed

phpstan-baseline.neon

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ parameters:
5454
count: 1
5555
path: src/Bridge/Faker/Provider/StoryblokProvider.php
5656

57+
-
58+
message: '#^Method Storyblok\\Api\\Bridge\\Faker\\Provider\\StoryblokProvider\:\:richTextResponse\(\) should return array\{type\: string, content\: list\<array\<mixed\>\>\} but returns array\.$#'
59+
identifier: return.type
60+
count: 1
61+
path: src/Bridge/Faker/Provider/StoryblokProvider.php
62+
5763
-
5864
message: '#^Method Storyblok\\Api\\Bridge\\Faker\\Provider\\StoryblokProvider\:\:spaceResponse\(\) should return array\{id\: int, name\: string, domain\: string, version\: int, language_codes\: list\<string\>\} but returns array\.$#'
5965
identifier: return.type

src/Bridge/Faker/Generator.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
* @method array linkResponse(array $overrides = [])
3232
* @method array linksResponse(array $overrides = [])
3333
* @method string relation()
34+
* @method array richTextEmptyResponse()
35+
* @method array richTextParagraphResponse(?string $text = null)
36+
* @method array richTextResponse(array $overrides = [])
3437
* @method array spaceResponse(array $overrides = [])
3538
* @method array storiesResponse(array $overrides = [])
3639
* @method array storyResponse(array $overrides = [])

src/Bridge/Faker/Provider/StoryblokProvider.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,75 @@ public function assetResponse(array $overrides = []): array
505505
);
506506
}
507507

508+
/**
509+
* @param mixed[] $overrides
510+
*
511+
* @return array{
512+
* type: string,
513+
* content: list<mixed[]>,
514+
* }
515+
*/
516+
public function richTextResponse(array $overrides = []): array
517+
{
518+
$response = [
519+
'type' => 'doc',
520+
'content' => [
521+
[
522+
'type' => 'paragraph',
523+
'content' => [
524+
[
525+
'type' => 'text',
526+
'text' => $this->generator->sentence(),
527+
],
528+
],
529+
],
530+
],
531+
];
532+
533+
return array_replace_recursive(
534+
$response,
535+
$overrides,
536+
);
537+
}
538+
539+
/**
540+
* @return array{
541+
* type: 'doc',
542+
* content: list<mixed[]>
543+
* }
544+
*/
545+
public function richTextParagraphResponse(?string $text = null): array
546+
{
547+
return [
548+
'type' => 'doc',
549+
'content' => [
550+
[
551+
'type' => 'paragraph',
552+
'content' => [
553+
[
554+
'type' => 'text',
555+
'text' => $text,
556+
],
557+
],
558+
],
559+
],
560+
];
561+
}
562+
563+
/**
564+
* @return array{
565+
* type: 'doc',
566+
* content: list<mixed[]>
567+
* }
568+
*/
569+
public function richTextEmptyResponse(): array
570+
{
571+
return [
572+
'type' => 'doc',
573+
'content' => [],
574+
];
575+
}
576+
508577
public function relation(): string
509578
{
510579
return \sprintf(

src/Domain/Type/RichText.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Type;
16+
17+
use OskarStark\Value\TrimmedNonEmptyString;
18+
use Webmozart\Assert\Assert;
19+
20+
/**
21+
* @experimental This class is experimental and may change in future versions.
22+
*
23+
* @author Silas Joisten <[email protected]>
24+
*/
25+
final readonly class RichText
26+
{
27+
public string $type;
28+
29+
/**
30+
* @var list<mixed[]>
31+
*/
32+
public array $content;
33+
34+
/**
35+
* @param array<string, mixed> $values
36+
*/
37+
public function __construct(array $values)
38+
{
39+
Assert::keyExists($values, 'type');
40+
$this->type = TrimmedNonEmptyString::fromString($values['type'])->toString();
41+
Assert::same($this->type, 'doc');
42+
43+
Assert::keyExists($values, 'content');
44+
Assert::isList($values['content']);
45+
$this->content = $values['content'];
46+
}
47+
48+
/**
49+
* @return array{
50+
* type: string,
51+
* content: list<mixed[]>,
52+
* }
53+
*/
54+
public function toArray(): array
55+
{
56+
return [
57+
'type' => $this->type,
58+
'content' => $this->content,
59+
];
60+
}
61+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Tests\Unit\Domain\Type;
16+
17+
use PHPUnit\Framework\Attributes\Test;
18+
use PHPUnit\Framework\TestCase;
19+
use Storyblok\Api\Domain\Type\RichText;
20+
use Storyblok\Api\Tests\Util\FakerTrait;
21+
22+
/**
23+
* @author Silas Joisten <[email protected]>
24+
*/
25+
final class RichTextTest extends TestCase
26+
{
27+
use FakerTrait;
28+
29+
#[Test]
30+
public function type(): void
31+
{
32+
$values = self::faker()->richTextResponse([
33+
'type' => $expected = 'doc',
34+
]);
35+
36+
self::assertSame($expected, (new RichText($values))->type);
37+
}
38+
39+
#[Test]
40+
public function typeKeyMustExist(): void
41+
{
42+
$values = self::faker()->richTextResponse();
43+
unset($values['type']);
44+
45+
self::expectException(\InvalidArgumentException::class);
46+
47+
new RichText($values);
48+
}
49+
50+
#[Test]
51+
public function typeKeyMustBeTrimmedNonEmptyString(): void
52+
{
53+
$values = self::faker()->richTextResponse([
54+
'type' => ' ',
55+
]);
56+
57+
self::expectException(\InvalidArgumentException::class);
58+
59+
new RichText($values);
60+
}
61+
62+
#[Test]
63+
public function contentKeyMustExist(): void
64+
{
65+
$values = self::faker()->richTextResponse();
66+
unset($values['content']);
67+
68+
self::expectException(\InvalidArgumentException::class);
69+
70+
new RichText($values);
71+
}
72+
73+
#[Test]
74+
public function content(): void
75+
{
76+
$values = self::faker()->richTextResponse([
77+
'content' => $expected = ['foo', 'bar'],
78+
]);
79+
80+
self::assertSame($expected, (new RichText($values))->content);
81+
}
82+
83+
#[Test]
84+
public function contentCanBeEmptyArray(): void
85+
{
86+
$values = self::faker()->richTextEmptyResponse();
87+
88+
self::assertEmpty((new RichText($values))->content);
89+
}
90+
}

0 commit comments

Comments
 (0)