Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.

Commit 4bcc306

Browse files
committed
refactoring
1 parent 82af1b7 commit 4bcc306

File tree

15 files changed

+262
-231
lines changed

15 files changed

+262
-231
lines changed
Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,20 @@
1111

1212
declare(strict_types=1);
1313

14-
namespace Devscast\EditorJs\Blocks;
15-
16-
use Devscast\EditorJs\Assert;
17-
use Devscast\EditorJs\Sanitizer;
14+
namespace Devscast\EditorJs;
1815

1916
/**
20-
* Class Block.
17+
* Class AbstractBlock.
2118
*
2219
* @phpstan-consistent-constructor
2320
*
2421
* @author bernard-ng <bernard@devscast.tech>
2522
*/
26-
abstract readonly class Block
23+
abstract readonly class AbstractBlock implements BlockInterface
2724
{
28-
public function __construct(
25+
public const string NAME = 'abstract';
26+
27+
protected function __construct(
2928
public string $id,
3029
public string $type,
3130
public array $data,
@@ -35,8 +34,6 @@ public function __construct(
3534
Assert::notEmpty($id);
3635
}
3736

38-
abstract public function toHtml(): string;
39-
4037
public static function create(array $data, array $allowedTags = []): static
4138
{
4239
return new static(
@@ -54,4 +51,23 @@ public function sanitize(): string
5451

5552
return $sanitizer->sanitize($this->toHtml());
5653
}
54+
55+
#[\Override]
56+
public function getName(): string
57+
{
58+
return static::NAME;
59+
}
60+
61+
#[\Override]
62+
public function getSchema(): array
63+
{
64+
$filename = sprintf('%s/schemas/%s.schema.json', dirname(__DIR__), $this->getName());
65+
$content = file_get_contents($filename);
66+
Assert::string($content, sprintf('Schema for block type %s not found', $this->getName()));
67+
68+
/** @var array $schema */
69+
$schema = json_decode($content, true);
70+
71+
return $schema;
72+
}
5773
}

src/BlockFactory.php

Lines changed: 35 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
namespace Devscast\EditorJs;
1515

1616
use Devscast\EditorJs\Blocks\Attaches;
17-
use Devscast\EditorJs\Blocks\Block;
1817
use Devscast\EditorJs\Blocks\Code;
1918
use Devscast\EditorJs\Blocks\Delimiter;
2019
use Devscast\EditorJs\Blocks\Embed;
@@ -27,7 +26,6 @@
2726
use Devscast\EditorJs\Blocks\Table;
2827
use Devscast\EditorJs\Blocks\Warning;
2928
use Devscast\EditorJs\Exception\EditorException;
30-
use Swaggest\JsonSchema\Schema;
3129

3230
/**
3331
* Class BlockFactory.
@@ -36,30 +34,33 @@
3634
*/
3735
abstract class BlockFactory
3836
{
39-
/**
40-
* @throws EditorException
41-
*
42-
* reduire la complexite de O(n) a O(1) evitant de tout le temps checker toutes les conditions
43-
*/
44-
private static array $blockFactories = [];
37+
public const array SUPPORTED_BLOCKS = [
38+
Attaches::NAME,
39+
Code::NAME,
40+
Delimiter::NAME,
41+
Embed::NAME,
42+
Header::NAME,
43+
Image::NAME,
44+
Listing::NAME,
45+
Paragraph::NAME,
46+
Quote::NAME,
47+
Raw::NAME,
48+
Table::NAME,
49+
Warning::NAME,
50+
];
4551

4652
/**
4753
* @throws EditorException
4854
*/
49-
public static function parse(string $data, ?array $tools = null, array $allowedTags = []): array
55+
public static function parse(string $data, ?array $supportedBlocks = self::SUPPORTED_BLOCKS, array $allowedTags = []): array
5056
{
5157
try {
5258
/** @var array{time: int, blocks: array<array{id: string, type: string, data: mixed}>} $blocks */
5359
$blocks = json_decode($data, true, flags: JSON_THROW_ON_ERROR);
54-
$mapper = fn (array $block): Block => self::create($block, self::getAllowedTags($block, $allowedTags));
60+
$mapper = fn (array $block): AbstractBlock => self::create($block, self::getAllowedTags($block, $allowedTags));
5561

56-
// TODO: whitelist tools and supported blocks
57-
// if ($tools !== null) {
58-
// $blocks = self::filter($blocks['blocks'], $tools);
59-
// }
60-
61-
if ($tools !== null) {
62-
$blocks['blocks'] = self::filter($blocks['blocks'], $tools);
62+
if ($supportedBlocks !== null) {
63+
$blocks['blocks'] = self::filter($blocks['blocks'], $supportedBlocks);
6364

6465
if (empty($blocks['blocks'])) {
6566
throw new EditorException('No valid blocks found after filtering');
@@ -72,47 +73,28 @@ public static function parse(string $data, ?array $tools = null, array $allowedT
7273
}
7374
}
7475

75-
// private static function filter(array $data, array $tools): array
76-
// {
77-
// return array_filter($data, fn (array $block): bool => isset($tools[$block['type']]));
78-
// }
79-
80-
private static function filter(array $blocks, array $tools): array
81-
{
82-
return array_filter($blocks, fn (array $block) => in_array($block['type'], $tools, true));
83-
}
84-
85-
private static function initializeFactories(): void
76+
private static function filter(array $blocks, array $supportedBlocks): array
8677
{
87-
if (self::$blockFactories !== []) {
88-
return;
89-
}
90-
self::$blockFactories = [
91-
'attaches' => static fn (array $data, array $allowedTags) => Attaches::create($data, $allowedTags),
92-
'code' => static fn (array $data, array $allowedTags) => Code::create($data, $allowedTags),
93-
'delimiter' => static fn (array $data, array $allowedTags) => Delimiter::create($data, $allowedTags),
94-
'embed' => static fn (array $data, array $allowedTags) => Embed::create($data, $allowedTags),
95-
'header' => static fn (array $data, array $allowedTags) => Header::create($data, $allowedTags),
96-
'image' => static fn (array $data, array $allowedTags) => Image::create($data, $allowedTags),
97-
'list' => static fn (array $data, array $allowedTags) => Listing::create($data, $allowedTags),
98-
'paragraph' => static fn (array $data, array $allowedTags) => Paragraph::create($data, $allowedTags),
99-
'quote' => static fn (array $data, array $allowedTags) => Quote::create($data, $allowedTags),
100-
'raw' => static fn (array $data, array $allowedTags) => Raw::create($data, $allowedTags),
101-
'table' => static fn (array $data, array $allowedTags) => Table::create($data, $allowedTags),
102-
'warning' => static fn (array $data, array $allowedTags) => Warning::create($data, $allowedTags),
103-
];
78+
return array_filter($blocks, fn (array $block) => in_array($block['type'], $supportedBlocks, true));
10479
}
10580

106-
private static function create(array $data, array $allowedTags = []): Block
81+
private static function create(array $data, array $allowedTags = []): AbstractBlock
10782
{
10883
try {
109-
self::initializeFactories();
110-
111-
$type = $data['type'];
112-
if (! isset(self::$blockFactories[$type])) {
113-
throw new EditorException(sprintf('Block type %s not supported', $type));
114-
}
115-
return self::$blockFactories[$type]($data, $allowedTags);
84+
return match ($data['type']) {
85+
'attaches' => Attaches::create($data, $allowedTags),
86+
'code' => Code::create($data, $allowedTags),
87+
'delimiter' => Delimiter::create($data, $allowedTags),
88+
'embed' => Embed::create($data, $allowedTags),
89+
'header' => Header::create($data, $allowedTags),
90+
'image' => Image::create($data, $allowedTags),
91+
'list' => Listing::create($data, $allowedTags),
92+
'paragraph' => Paragraph::create($data, $allowedTags),
93+
'quote' => Quote::create($data, $allowedTags),
94+
'raw' => Raw::create($data, $allowedTags),
95+
'table' => Table::create($data, $allowedTags),
96+
'warning' => Warning::create($data, $allowedTags),
97+
};
11698
} catch (\Throwable $e) {
11799
throw new EditorException($e->getMessage(), previous: $e);
118100
}
@@ -124,16 +106,4 @@ private static function getAllowedTags(array $block, array $allowedTags): array
124106

125107
return $allowedTags[$block['type']] ?? [];
126108
}
127-
128-
// private static function getSchema(string $schema): array
129-
// {
130-
// $filename = sprintf('%s/schemas/%s.schema.json', dirname(__DIR__), $schema);
131-
// $content = file_get_contents($filename);
132-
// Assert::string($content, sprintf('Schema for block type %s not found', $schema));
133-
//
134-
// /** @var array $schema */
135-
// $schema = json_decode($content, true);
136-
//
137-
// return $schema;
138-
// }
139109
}

src/BlockInterface.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Devscast\EditorJs;
6+
7+
/**
8+
* Interface BlockInterface.
9+
*
10+
* @author bernard-ng <bernard@devscast.tech>
11+
*/
12+
interface BlockInterface
13+
{
14+
public function getName(): string;
15+
16+
public function toHtml(): string;
17+
18+
public function getSchema(): array;
19+
}

src/Blocks/Attaches.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,26 @@
1313

1414
namespace Devscast\EditorJs\Blocks;
1515

16+
use Devscast\EditorJs\AbstractBlock;
1617
use Devscast\EditorJs\Assert;
1718

1819
/**
1920
* Class Attaches.
2021
*
21-
* File attachments Block for the Editor.js
22+
* File attachments AbstractBlock for the Editor.js
2223
*
2324
* @see https://github.com/editor-js/attaches
2425
* @see https://raw.githubusercontent.com/devscast/editorjs-sanitizer/refs/heads/main/schemas/warning.schema.json
2526
*
2627
* @author bernard-ng <bernard@devscast.tech>
2728
*/
28-
final readonly class Attaches extends Block
29+
final readonly class Attaches extends AbstractBlock
2930
{
30-
public function __construct(string $id, string $type, array $data, ?array $tunes = [], ?array $allowedTags = null)
31+
public const string NAME = 'attaches';
32+
33+
protected function __construct(string $id, string $type, array $data, ?array $tunes = [], ?array $allowedTags = null)
3134
{
32-
Assert::eq($type, 'attaches');
35+
Assert::eq($type, self::NAME);
3336
Assert::keyExists($data, 'file');
3437
Assert::keyExists($data['file'], 'url');
3538
Assert::keyExists($data['file'], 'size');
@@ -44,11 +47,11 @@ public function __construct(string $id, string $type, array $data, ?array $tunes
4447
public function toHtml(): string
4548
{
4649
return <<<HTML
47-
<div id="{$this->id}">
48-
<a href="{$this->data['file']['url']}" title="{$this->data['title']}">
49-
<strong>{$this->data['file']['name']}</strong> ({$this->data['file']['size']} bytes)
50-
</a>
51-
</div>
50+
<div id="{$this->id}">
51+
<a href="{$this->data['file']['url']}" title="{$this->data['title']}">
52+
<strong>{$this->data['file']['name']}</strong> ({$this->data['file']['size']} bytes)
53+
</a>
54+
</div>
5255
HTML;
5356
}
5457
}

src/Blocks/Code.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace Devscast\EditorJs\Blocks;
1515

16+
use Devscast\EditorJs\AbstractBlock;
1617
use Devscast\EditorJs\Assert;
1718

1819
/**
@@ -25,11 +26,13 @@
2526
*
2627
* @author bernard-ng <bernard@devscast.tech>
2728
*/
28-
final readonly class Code extends Block
29+
final readonly class Code extends AbstractBlock
2930
{
30-
public function __construct(string $id, string $type, array $data, ?array $tunes = [], ?array $allowedTags = null)
31+
public const string NAME = 'code';
32+
33+
protected function __construct(string $id, string $type, array $data, ?array $tunes = [], ?array $allowedTags = null)
3134
{
32-
Assert::eq($type, 'code');
35+
Assert::eq($type, self::NAME);
3336
Assert::keyExists($data, 'code');
3437

3538
parent::__construct($id, $type, $data, $tunes, $allowedTags);
@@ -38,12 +41,10 @@ public function __construct(string $id, string $type, array $data, ?array $tunes
3841
#[\Override]
3942
public function toHtml(): string
4043
{
41-
return trim(
42-
<<<HTML
43-
<pre id="{$this->id}">
44-
<code>{$this->data['code']}</code>
45-
</pre>
46-
HTML
47-
);
44+
return <<<HTML
45+
<pre id="{$this->id}">
46+
<code>{$this->data['code']}</code>
47+
</pre>
48+
HTML;
4849
}
4950
}

src/Blocks/Delimiter.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace Devscast\EditorJs\Blocks;
1515

16+
use Devscast\EditorJs\AbstractBlock;
1617
use Devscast\EditorJs\Assert;
1718

1819
/**
@@ -25,20 +26,22 @@
2526
*
2627
* @author bernard-ng <bernard@devscast.tech>
2728
*/
28-
final readonly class Delimiter extends Block
29+
final readonly class Delimiter extends AbstractBlock
2930
{
30-
public function __construct(string $id, string $type, array $data, ?array $tunes = [], ?array $allowedTags = null)
31+
public const string NAME = 'delimiter';
32+
33+
protected function __construct(string $id, string $type, array $data, ?array $tunes = [], ?array $allowedTags = null)
3134
{
32-
Assert::eq($type, 'delimiter');
35+
Assert::eq($type, self::NAME);
3336

3437
parent::__construct($id, $type, $data, $tunes, $allowedTags);
3538
}
3639

3740
#[\Override]
3841
public function toHtml(): string
3942
{
40-
return trim(<<<HTML
41-
<hr id="{$this->id}">
42-
HTML);
43+
return <<<HTML
44+
<hr id="{$this->id}">
45+
HTML;
4346
}
4447
}

0 commit comments

Comments
 (0)