Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow direct append for nodes for complex composition #16

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,42 @@ $document = (new Document())
```


### Alternative usage
Alternatively, it is possible to compose a document using node objects directly via the `BlockNode::append` method.

```php
$document = (new Document())
->append(
(new BulletList())
->append(
(new ListItem())
->append(
(new Paragraph())
->append(new Text('item 1'))
),
(new ListItem())
->append(
(new Paragraph())
->append(new Text('item 2'))
)

)
)
;
```

In this case, it will be possible to create and append nodes dynamically:
```php
$paragraph = (new Paragraph())->append(new Text('Line 1'));

if (some condition) {
$paragraph->append(new Text('(doc)', new Link('https://example.com/doc')));
}

$document = (new Document())->append($paragraph);
```


### Loading an ADF JSON document

```php
Expand Down
3 changes: 2 additions & 1 deletion src/Builder/BuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

namespace DH\Adf\Builder;

use DH\Adf\Node\BlockNode;
use DH\Adf\Node\Node;

trait BuilderInterface
{
abstract protected function append(Node $node): void;
abstract public function append(Node ...$nodes): BlockNode;
}
3 changes: 2 additions & 1 deletion src/Builder/InlineNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace DH\Adf\Builder;

use DH\Adf\Node\BlockNode;
use DH\Adf\Node\Inline\Emoji;
use DH\Adf\Node\Inline\Hardbreak;
use DH\Adf\Node\Inline\Mention;
Expand Down Expand Up @@ -34,5 +35,5 @@ public function break(?Node $parent = null): self
return $this;
}

abstract protected function append(Node $node): void;
abstract public function append(Node ...$nodes): BlockNode;
}
3 changes: 2 additions & 1 deletion src/Builder/TextBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace DH\Adf\Builder;

use DH\Adf\Node\BlockNode;
use DH\Adf\Node\Inline\Text;
use DH\Adf\Node\Mark\Em;
use DH\Adf\Node\Mark\Link;
Expand Down Expand Up @@ -79,5 +80,5 @@ public function link(string $text, string $href, ?string $title = null): self
return $this;
}

abstract protected function append(Node $node): void;
abstract public function append(Node ...$nodes): BlockNode;
}
23 changes: 18 additions & 5 deletions src/Node/BlockNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,29 @@ public function getContent(): array
return $this->content;
}

protected function append(Node $node): void
public function append(Node ...$nodes): BlockNode
{
foreach ($this->allowedContentTypes as $type) {
if ($node instanceof $type) {
foreach ($nodes as $node) {
if ($this->isAppendAllowed($node)) {
$this->content[] = $node;
} else {
throw new InvalidArgumentException(
sprintf('Invalid content type "%s" for block node "%s".', $node->getType(), $this->getType())
);
}
}

return;
return $this;
}

protected function isAppendAllowed(Node $node): bool
{
foreach ($this->allowedContentTypes as $allowedContentType) {
if ($node instanceof $allowedContentType) {
return true;
}
}

throw new InvalidArgumentException(sprintf('Invalid content type "%s" for block node "%s".', $node->type, $this->type));
return false;
}
}
5 changes: 5 additions & 0 deletions src/Node/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ public static function load(array $data): self
return $node;
}

public function getType(): string
{
return $this->type;
}

protected function attrs(): array
{
return [];
Expand Down
189 changes: 189 additions & 0 deletions tests/Node/Block/DirectAppendTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php

declare(strict_types=1);

namespace DH\Adf\Tests\Node\Block;

use DH\Adf\Node\Block\Document;
use DH\Adf\Node\Block\Panel;
use DH\Adf\Node\Block\Paragraph;
use DH\Adf\Node\Inline\Text;
use DH\Adf\Node\Mark\Em;
use DH\Adf\Node\Mark\Link;
use DH\Adf\Node\Mark\Strike;
use DH\Adf\Node\Mark\Strong;
use DH\Adf\Node\Mark\Subsup;
use DH\Adf\Node\Mark\TextColor;
use DH\Adf\Node\Mark\Underline;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;

/**
* @internal
*
* @small
*/
class DirectAppendTest extends TestCase
{
public function testDocumentWithEmptyParagraph(): void
{
$document = (new Document())
->append(
new Paragraph()
)
;

$doc = json_encode($document);

self::assertJsonStringEqualsJsonString($doc, json_encode([
'version' => 1,
'type' => 'doc',
'content' => [
[
'type' => 'paragraph',
'content' => [],
],
],
]));
}

public function testDocumentWithTextInParagraph(): void
{
$document = (new Document())
->append(
(new Paragraph())
->append(
new Text('Luke, ', new TextColor('red')),
new Text('may '),
new Text('the ', new Em()),
new Text('force ', new Strong()),
new Text('be '),
new Text('with ', new Underline()),
new Text('you! ', new Strike()),
new Text('Obi-Wan', new Subsup('sub')),
new Text('Kenobi', new Subsup('sup')),
new Text('Star Wars @ Wikipedia', new Link('https://wikipedia.org/wiki/Star_Wars'))
),
)
;

$doc = json_encode($document);

self::assertJsonStringEqualsJsonString($doc, json_encode([
'version' => 1,
'type' => 'doc',
'content' => [
[
'type' => 'paragraph',
'content' => [
[
'type' => 'text',
'text' => 'Luke, ',
'marks' => [
[
'type' => 'textColor',
'attrs' => [
'color' => 'red',
],
],
],
],
[
'type' => 'text',
'text' => 'may ',
],
[
'type' => 'text',
'text' => 'the ',
'marks' => [
[
'type' => 'em',
],
],
],
[
'type' => 'text',
'text' => 'force ',
'marks' => [
[
'type' => 'strong',
],
],
],
[
'type' => 'text',
'text' => 'be ',
],
[
'type' => 'text',
'text' => 'with ',
'marks' => [
[
'type' => 'underline',
],
],
],
[
'type' => 'text',
'text' => 'you! ',
'marks' => [
[
'type' => 'strike',
],
],
],
[
'type' => 'text',
'text' => 'Obi-Wan',
'marks' => [
[
'type' => 'subsup',
'attrs' => [
'type' => 'sub',
],
],
],
],
[
'type' => 'text',
'text' => 'Kenobi',
'marks' => [
[
'type' => 'subsup',
'attrs' => [
'type' => 'sup',
],
],
],
],
[
'type' => 'text',
'text' => 'Star Wars @ Wikipedia',
'marks' => [
[
'type' => 'link',
'attrs' => [
'href' => 'https://wikipedia.org/wiki/Star_Wars',
],
],
],
],
],
],
],
]));
}

public function testIllegalAppend()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid content type "panel" for block node "paragraph".');

(new Document())
->append(
(new Paragraph())
->append(new Panel())
)
;
}
}
Loading