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

Commit 947aa8d

Browse files
authored
Merge pull request #1 from devscast/dev
issue with sanitize
2 parents 97a3b5d + 4bcc306 commit 947aa8d

33 files changed

+2415
-189
lines changed

.github/workflows/lint.yaml

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
1-
name: Lint
2-
on: [push, pull_request]
1+
name: Coding standards
2+
on: [push]
33
jobs:
4-
lint:
5-
name: PHP Lint
6-
runs-on: ubuntu-latest
7-
steps:
8-
- name: Setup PHP
9-
uses: shivammathur/setup-php@v2
10-
with:
11-
php-version: 8.3
4+
lint:
5+
name: Coding standards
6+
runs-on: ubuntu-latest
7+
strategy:
8+
fail-fast: false
9+
matrix:
10+
php: [ '8.3', '8.4' ]
1211

13-
- name: Cache Composer dependencies
14-
uses: actions/cache@v4
15-
with:
16-
path: /tmp/composer-cache
17-
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
1815

19-
- uses: actions/checkout@v4
20-
- name: lint
21-
run: make app:lint
16+
- name: Setup PHP
17+
uses: shivammathur/setup-php@v2
18+
with:
19+
php-version: ${{ matrix.php }}
20+
tools: composer:v2
21+
22+
- name: Setup cache
23+
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
24+
25+
- name: Cache dependencies installed with composer
26+
uses: actions/cache@v4
27+
with:
28+
path: ${{ env.COMPOSER_CACHE_DIR }}
29+
key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
30+
restore-keys: |
31+
php${{ matrix.php }}-composer-latest-
32+
33+
- name: Update composer
34+
run: composer self-update
35+
36+
- name: Install dependencies with composer
37+
run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
38+
39+
- name: Run code quality analysis
40+
run: composer app:lint

.github/workflows/test.yaml

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
1-
name: Test
2-
on: [push, pull_request]
1+
name: Tests
2+
on: [push]
33
jobs:
4-
lint:
5-
name: PHP Test
6-
runs-on: ubuntu-latest
7-
steps:
8-
- name: Setup PHP
9-
uses: shivammathur/setup-php@v2
10-
with:
11-
php-version: 8.3
4+
test:
5+
name: Tests
6+
runs-on: ubuntu-latest
7+
strategy:
8+
fail-fast: false
9+
matrix:
10+
php: [ '8.3', '8.4' ]
1211

13-
- name: Cache Composer dependencies
14-
uses: actions/cache@v4
15-
with:
16-
path: /tmp/composer-cache
17-
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
1815

19-
- uses: actions/checkout@v4
20-
- name: test
21-
run: make app:test
16+
- name: Setup PHP
17+
uses: shivammathur/setup-php@v2
18+
with:
19+
php-version: ${{ matrix.php }}
20+
tools: composer:v2
21+
22+
- name: Setup cache
23+
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
24+
25+
- name: Cache dependencies installed with composer
26+
uses: actions/cache@v4
27+
with:
28+
path: ${{ env.COMPOSER_CACHE_DIR }}
29+
key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
30+
restore-keys: |
31+
php${{ matrix.php }}-composer-latest-
32+
33+
- name: Update composer
34+
run: composer self-update
35+
36+
- name: Install dependencies with composer
37+
run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
38+
39+
- name: Run tests
40+
run: composer app:test

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
],
4242
"app:lint:fix": [
4343
"vendor/bin/ecs check --fix",
44-
"venodr/bin/rector"
44+
"vendor/bin/rector"
4545
],
4646
"app:test": "vendor/bin/phpunit"
4747
}

composer.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/AbstractBlock.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the EditorJs Sanitizer package.
5+
*
6+
* (c) Bernard Ngandu <bernard@devscast.tech>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Devscast\EditorJs;
15+
16+
/**
17+
* Class AbstractBlock.
18+
*
19+
* @phpstan-consistent-constructor
20+
*
21+
* @author bernard-ng <bernard@devscast.tech>
22+
*/
23+
abstract readonly class AbstractBlock implements BlockInterface
24+
{
25+
public const string NAME = 'abstract';
26+
27+
protected function __construct(
28+
public string $id,
29+
public string $type,
30+
public array $data,
31+
public ?array $tunes = null,
32+
public ?array $allowedTags = null,
33+
) {
34+
Assert::notEmpty($id);
35+
}
36+
37+
public static function create(array $data, array $allowedTags = []): static
38+
{
39+
return new static(
40+
id: $data['id'],
41+
type: $data['type'],
42+
data: $data['data'],
43+
tunes: $data['tunes'] ?? null,
44+
allowedTags: $allowedTags
45+
);
46+
}
47+
48+
public function sanitize(): string
49+
{
50+
$sanitizer = Sanitizer::create($this->allowedTags ?? []);
51+
52+
return $sanitizer->sanitize($this->toHtml());
53+
}
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+
}
73+
}

src/BlockFactory.php

Lines changed: 29 additions & 31 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,26 +26,45 @@
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.
3432
*
3533
* @author bernard-ng <bernard@devscast.tech>
3634
*/
37-
abstract readonly class BlockFactory
35+
abstract class BlockFactory
3836
{
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+
];
51+
3952
/**
4053
* @throws EditorException
4154
*/
42-
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
4356
{
4457
try {
58+
/** @var array{time: int, blocks: array<array{id: string, type: string, data: mixed}>} $blocks */
4559
$blocks = json_decode($data, true, flags: JSON_THROW_ON_ERROR);
46-
$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));
61+
62+
if ($supportedBlocks !== null) {
63+
$blocks['blocks'] = self::filter($blocks['blocks'], $supportedBlocks);
4764

48-
if ($tools !== null) {
49-
$blocks = self::filter($blocks['blocks'], $tools);
65+
if (empty($blocks['blocks'])) {
66+
throw new EditorException('No valid blocks found after filtering');
67+
}
5068
}
5169

5270
return array_map($mapper, $blocks['blocks']);
@@ -55,25 +73,14 @@ public static function parse(string $data, ?array $tools = null, array $allowedT
5573
}
5674
}
5775

58-
private static function filter(array $data, array $tools): array
76+
private static function filter(array $blocks, array $supportedBlocks): array
5977
{
60-
return array_filter($data, fn (array $block): bool => isset($tools[$block['type']]));
78+
return array_filter($blocks, fn (array $block) => in_array($block['type'], $supportedBlocks, true));
6179
}
6280

63-
/**
64-
* @throws EditorException
65-
*/
66-
private static function create(array $data, array $allowedTags = []): Block
81+
private static function create(array $data, array $allowedTags = []): AbstractBlock
6782
{
6883
try {
69-
// TODO: I think this may be very slow for large data need to think of a better way
70-
71-
//dd(self::getSchema($data['type']), $data);
72-
73-
$schema = Schema::import(self::getSchema($data['type']));
74-
75-
dd($schema);
76-
7784
return match ($data['type']) {
7885
'attaches' => Attaches::create($data, $allowedTags),
7986
'code' => Code::create($data, $allowedTags),
@@ -93,19 +100,10 @@ private static function create(array $data, array $allowedTags = []): Block
93100
}
94101
}
95102

96-
private static function getAllowedTags(mixed $block, array $allowedTags): array
103+
private static function getAllowedTags(array $block, array $allowedTags): array
97104
{
98105
Assert::keyExists($block, 'type');
99106

100107
return $allowedTags[$block['type']] ?? [];
101108
}
102-
103-
private static function getSchema(string $schema): array
104-
{
105-
$filename = sprintf("%s/schemas/%s.schema.json", dirname(__DIR__), $schema);
106-
$content = file_get_contents($filename);
107-
Assert::string($content, sprintf('Schema for block type %s not found', $schema));
108-
109-
return json_decode($content, true);
110-
}
111109
}

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+
}

0 commit comments

Comments
 (0)