Skip to content

Commit 039712b

Browse files
committed
Initial checkin of the rewrite for webfactory/html5-tagrewriter, the HTML5 DOM parser-based version 🦄
0 parents  commit 039712b

25 files changed

Lines changed: 1109 additions & 0 deletions

.github/workflows/dependencies.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Dependencies
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
env:
10+
PHP_VERSION: 8.4
11+
12+
jobs:
13+
composer-require-checker:
14+
name: Check missing composer requirements
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: shivammathur/setup-php@v2
19+
with:
20+
php-version: ${{ env.PHP_VERSION }}
21+
coverage: none
22+
tools: composer:v2
23+
- run: |
24+
composer install --no-interaction --no-scripts --no-progress --ansi
25+
composer show
26+
- uses: docker://ghcr.io/webfactory/composer-require-checker:4.19.0

.github/workflows/fix-cs-php.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Coding Standards
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
fix-cs-violations:
11+
name: Apply PHP-CS-Fixer
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
with:
17+
ref: ${{ github.head_ref }}
18+
19+
- name: Run PHP-CS-Fixer
20+
uses: docker://ghcr.io/php-cs-fixer/php-cs-fixer:3.89.2-php8.4
21+
with:
22+
args: "fix --show-progress=dots"
23+
24+
- name: Commit and push back changes
25+
uses: stefanzweifel/git-auto-commit-action@v5
26+
with:
27+
commit_message: "Fix CS with PHP-CS-Fixer"

.github/workflows/tests.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
PHPUnit:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
include:
16+
- { php-version: 8.4, symfony-version: '6.4.*' }
17+
- { php-version: 8.4, symfony-version: '7.4.*' }
18+
- { php-version: 8.4, symfony-version: '8.*' }
19+
- { php-version: 8.5, symfony-version: '8.*' }
20+
name: PHPUnit (PHP ${{matrix.php-version}}, Symfony ${{ matrix.symfony-version }})
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: shivammathur/setup-php@v2
24+
with:
25+
php-version: ${{ matrix.php-version }}
26+
coverage: none
27+
tools: composer:v2, flex
28+
- run: composer update --no-interaction --no-scripts --no-progress --ansi
29+
env:
30+
SYMFONY_REQUIRE: ${{ matrix.symfony-version }}
31+
- run: composer show
32+
- run: vendor/bin/phpunit --display-all

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
composer.lock
2+
vendor/
3+
.*.cache
4+
tests/Fixtures/var

.php-cs-fixer.dist.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
return (new PhpCsFixer\Config())
4+
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
5+
->setRules([
6+
'@Symfony' => true,
7+
'phpdoc_separation' => false,
8+
'@Symfony:risky' => true,
9+
'array_syntax' => array('syntax' => 'short'),
10+
'no_unreachable_default_argument_value' => false,
11+
'braces' => array('allow_single_line_closure' => true),
12+
'heredoc_to_nowdoc' => false,
13+
'phpdoc_annotation_without_dot' => false,
14+
'php_unit_test_annotation' => false,
15+
'php_unit_method_casing' => false,
16+
'global_namespace_import' => ['import_classes' => true, 'import_constants' => false, 'import_functions' => false],
17+
'psr_autoloading' => false,
18+
])
19+
->setRiskyAllowed(true)
20+
->setFinder(
21+
PhpCsFixer\Finder::create()
22+
->in(__DIR__)
23+
->notPath('vendor/')
24+
->notPath('tests/Fixtures/var')
25+
)
26+
;

.php_cs.dist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
return PhpCsFixer\Config::create()
4+
->setRules([
5+
'@Symfony' => true,
6+
'@Symfony:risky' => true,
7+
'@PHPUnit48Migration:risky' => true,
8+
'array_syntax' => ['syntax' => 'short'],
9+
'fopen_flags' => false,
10+
'ordered_imports' => true,
11+
'protected_to_private' => false,
12+
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
13+
])
14+
->setRiskyAllowed(true)
15+
->setFinder(
16+
PhpCsFixer\Finder::create()
17+
->in([__DIR__])
18+
->append([__FILE__])
19+
->exclude([
20+
])
21+
)
22+
;

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Changelog for WebfactoryTagRewriterBundle
2+
--------------
3+
4+
## Version 2.0.0
5+
6+
- Der default-Modus ist jetzt nicht mehr `xhtml1`, sondern `html5`. Konfiguriere `xhtml1` ausdrücklich, wenn Du es benötigst. Wenn Du möchtest, kannst Du `html5` aus der Konfiguration entfernen.
7+
8+
## Version 1.6.1
9+
10+
- Es wird nicht mehr der erste definierte TagRewriter als default angenommen, sondern
11+
nur noch eine Definition mit einer expliziten `default="true"`-Angabe.
12+
13+
## Version 1.4.0
14+
15+
- Loads the webfactory.tag_rewriter service lazily

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2026 webfactory GmbH
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# WebfactoryHtml5TagRewriterBundle
2+
3+
This bundle provides Symfony integration for the [webfactory/html5-tagrewriter](https://github.com/webfactory/html5-tagrewriter) package.
4+
5+
Core feature is the Twig filter `rewriteTags`, which allows sections of HTML5 in Twig templates to be processed by RewriteHandlers. RewriteHandlers can be configured in the container through tags or using an autoconfiguration attribute.
6+
7+
See the [webfactory/html5-tagrewriter documentation](https://github.com/webfactory/html5-tagrewriter) for details on what a RewriteHandler is and how to implement one. Processing is based on the PHP 8.4 DOM HTML5 parser (`Dom\HTMLDocument`).
8+
9+
## Usage in Twig
10+
11+
Use the `rewriteTags` filter to process HTML through a TagRewriter:
12+
13+
```twig
14+
{# With the apply tag #}
15+
{% apply rewriteTags %}
16+
<a href="https://example.com">Link</a>
17+
{% endfilter %}
18+
19+
{# ... or the pipe notation #}
20+
{{ content|rewriteTags }}
21+
22+
{# Using a named TagRewriter #}
23+
{{ content|rewriteTags('special') }}
24+
```
25+
26+
## Registering RewriteHandlers
27+
28+
### Using the `#[AsRewriteHandler]` Attribute (Recommended)
29+
30+
The easiest way to register a RewriteHandler is using the `#[AsRewriteHandler]` attribute. With autowiring and autoconfiguration enabled, the handler will be automatically registered:
31+
32+
```php
33+
use Webfactory\Html5TagRewriter\Handler\BaseRewriteHandler;
34+
use Webfactory\Html5TagRewriterBundle\Attribute\AsRewriteHandler;
35+
use Dom\Element;
36+
37+
#[AsRewriteHandler]
38+
class MyRewriteHandler extends BaseRewriteHandler
39+
{
40+
public function appliesTo(): string
41+
{
42+
return '//html:a';
43+
}
44+
45+
public function match(Element $element): void
46+
{
47+
$element->setAttribute('target', '_blank');
48+
}
49+
}
50+
```
51+
52+
### Attribute Options
53+
54+
The `#[AsRewriteHandler]` attribute accepts two optional parameters:
55+
56+
- `priority` (int, default: `0`): Higher values are processed first
57+
- `rewriter` (string or array, default: `'default'`): The name(s) of the TagRewriter instance(s) to register with
58+
59+
```php
60+
// Register with high priority on the default rewriter
61+
#[AsRewriteHandler(priority: 100)]
62+
class HighPriorityHandler extends BaseRewriteHandler { /* ... */ }
63+
64+
// Register on a named rewriter
65+
#[AsRewriteHandler(rewriter: 'special')]
66+
class SpecialHandler extends BaseRewriteHandler { /* ... */ }
67+
68+
// Register on multiple rewriters
69+
#[AsRewriteHandler(rewriter: ['default', 'special'])]
70+
class SharedHandler extends BaseRewriteHandler { /* ... */ }
71+
72+
// Combine priority and named rewriter
73+
#[AsRewriteHandler(priority: 50, rewriter: 'special')]
74+
class PrioritizedSpecialHandler extends BaseRewriteHandler { /* ... */ }
75+
```
76+
77+
### Using Service Tags
78+
79+
If you need more control or cannot use autoconfiguration, you can manually tag your services with `webfactory.html5_tag_rewriter.rewrite_handler`:
80+
81+
```php
82+
// config/services.php
83+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
84+
85+
return static function (ContainerConfigurator $container): void {
86+
$services = $container->services();
87+
88+
$services->set(App\Handler\MyRewriteHandler::class)
89+
// ... arguments or other configuration here
90+
->tag('webfactory.html5_tag_rewriter.rewrite_handler');
91+
92+
$services->set(App\Handler\SpecialHandler::class)
93+
// ... arguments or other configuration here
94+
->tag('webfactory.html5_tag_rewriter.rewrite_handler', [
95+
'rewriter' => 'special',
96+
'priority' => 10,
97+
]);
98+
};
99+
```
100+
101+
## Credits, Copyright and License
102+
103+
This bundle is based on internal work that we have been using at webfactory GmbH, Bonn, since 2019.
104+
However, that (old) bundle implementation was written for the legacy PHP DOM extension, leading to
105+
several quirks in HTML processing and requiring the use of [Polyglot HTML 5](https://www.w3.org/TR/html-polyglot/).
106+
107+
Thus, we decided to overhaul the bundle for PHP 8.4 HTML5 DOM support and re-release it as open source.
108+
109+
- <https://www.webfactory.de>
110+
111+
Copyright 2026 webfactory GmbH, Bonn. Code released under [the MIT license](LICENSE).

composer.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "webfactory/html5-tagrewriter-bundle",
3+
"description": "Symfony bundle for webfactory/html5-tagrewriter integration",
4+
"type": "symfony-bundle",
5+
"license": "MIT",
6+
"keywords": [
7+
"html5",
8+
"dom",
9+
"rewriter",
10+
"transformer",
11+
"parser",
12+
"tagrewriter"
13+
],
14+
"authors": [
15+
{
16+
"name": "webfactory GmbH",
17+
"email": "info@webfactory.de",
18+
"homepage": "https://www.webfactory.de"
19+
}
20+
],
21+
"homepage": "https://github.com/webfactory/WebfactoryHtml5TagRewriterBundle",
22+
"require": {
23+
"php": ">= 8.4",
24+
"symfony/config": "^6.4 || ^7.4 || ^8.0",
25+
"symfony/dependency-injection": "^6.4 || ^7.4 || ^8.0",
26+
"symfony/http-kernel": "^6.4 || ^7.4 || ^8.0",
27+
"twig/twig": "^3.0",
28+
"webfactory/html5-tagrewriter": "dev-main"
29+
},
30+
"require-dev": {
31+
"phpunit/phpunit": "^12.5.6",
32+
"symfony/framework-bundle": "^6.4 || ^7.4 || ^8.0",
33+
"symfony/twig-bundle": "^6.4 || ^7.4 || ^8.0"
34+
},
35+
"autoload": {
36+
"psr-4": {
37+
"Webfactory\\Html5TagRewriterBundle\\": "src"
38+
}
39+
},
40+
"autoload-dev": {
41+
"psr-4": {
42+
"Webfactory\\Html5TagRewriterBundle\\Tests\\": "tests"
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)