Skip to content

Commit cbc438c

Browse files
authored
Merge pull request #52 from heahprod/configure-definition
[3.0] Fixed warming up custom configs and added support for custom config definition
2 parents e7105b9 + cee7c1a commit cbc438c

25 files changed

+953
-367
lines changed

.travis.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ cache:
1717
jobs:
1818
include:
1919
# Lowest
20-
- php: 5.5
21-
dist: trusty
22-
env: NO_FLEX=1 COMPOSER_FLAGS="--prefer-lowest" SYMFONY_DEPRECATIONS_HELPER=weak
2320
- php: 7.1
24-
env: SYMFONY_REQUIRE="4.3.*" COMPOSER_FLAGS="--prefer-lowest"
21+
env: COMPOSER_FLAGS="--prefer-lowest" SYMFONY_DEPRECATIONS_HELPER=weak
22+
- php: 7.1
23+
env: SYMFONY_REQUIRE="4.3.*" COMPOSER_FLAGS="--prefer-lowest" SYMFONY_DEPRECATIONS_HELPER=weak
2524

2625
# Stable
2726
- php: 7.2
@@ -54,7 +53,7 @@ jobs:
5453
before_install:
5554
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
5655
- composer self-update
57-
- if [[ -z $NO_FLEX ]]; then composer global require --no-progress --no-scripts --no-plugins symfony/flex; fi;
56+
- composer global require --no-progress --no-scripts --no-plugins symfony/flex
5857

5958
install:
6059
- composer update --prefer-dist --no-interaction $COMPOSER_FLAGS

CHANGELOG

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
## Version 3.0 (12/2019)
2+
3+
* [BC break] Dropped support for PHP 5.x. PHP 7.1 minimum required.
4+
* [BC break] Added type hints for scalar and return type hints where possible.
5+
* [BC Break] The bundle configuration has changed:
6+
```yaml
7+
# Before
8+
exercise_html_purifier:
9+
default:
10+
Cache.SerializerPath: '%kernel.cache_dir%/htmlpurifier'
11+
# ...
12+
custom:
13+
Core.Encoding: 'ISO-8859-1'
14+
15+
# After
16+
exercise_html_purifier:
17+
default_cache_serializer_path: '%kernel.cache_dir%/htmlpurifier'
18+
html_profiles:
19+
default:
20+
# ...
21+
custom:
22+
config:
23+
Core.Encoding: 'ISO-8859-1'
24+
```
25+
* Added an `HTMLPurifierConfigFactory` to handle cache and custom definitions.
26+
* Refactored `SerializerCacheWarmer` to preload each profile configuration
27+
128
## Version 2.0 (08/2018)
229

330
* Added compatibility for Symfony 5 and Twig 3

README.md

Lines changed: 173 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[![Total Downloads](https://poser.pugx.org/exercise/htmlpurifier-bundle/downloads)](https://packagist.org/packages/exercise/htmlpurifier-bundle)
22
[![Latest Stable Version](https://poser.pugx.org/exercise/htmlpurifier-bundle/v/stable)](https://packagist.org/packages/exercise/htmlpurifier-bundle)
33
[![License](https://poser.pugx.org/exercise/htmlpurifier-bundle/license)](https://packagist.org/packages/exercise/htmlpurifier-bundle)
4-
[![Build Status](https://travis-ci.org/Exercise/HTMLPurifierBundle.svg?branch=2.0)](https://travis-ci.org/Exercise/HTMLPurifierBundle)
4+
[![Build Status](https://travis-ci.org/Exercise/HTMLPurifierBundle.svg?branch=master)](https://travis-ci.org/Exercise/HTMLPurifierBundle)
55

66
# ExerciseHTMLPurifierBundle
77

@@ -36,14 +36,14 @@ Register the bundle in Symfony 3:
3636

3737
public function registerBundles()
3838
{
39-
return array(
40-
new Exercise\HTMLPurifierBundle\ExerciseHTMLPurifierBundle(),
39+
return [
4140
// ...
42-
);
41+
new Exercise\HTMLPurifierBundle\ExerciseHTMLPurifierBundle(),
42+
];
4343
}
4444
```
4545

46-
## Configuration in Symfony 3 without Symfony Flex
46+
## Configuration in Symfony 3
4747

4848
If you do not explicitly configure this bundle, an HTMLPurifier service will be
4949
defined as `exercise_html_purifier.default`. This behavior is the same as if you
@@ -53,8 +53,7 @@ had specified the following configuration:
5353
# app/config.yml
5454

5555
exercise_html_purifier:
56-
default:
57-
Cache.SerializerPath: '%kernel.cache_dir%/htmlpurifier'
56+
default_cache_serializer_path: '%kernel.cache_dir%/htmlpurifier'
5857
```
5958
6059
The `default` profile is special in that it is used as the configuration for the
@@ -65,10 +64,11 @@ other profiles you might define.
6564
# app/config.yml
6665
6766
exercise_html_purifier:
68-
default:
69-
Cache.SerializerPath: '%kernel.cache_dir%/htmlpurifier'
70-
custom:
71-
Core.Encoding: 'ISO-8859-1'
67+
default_cache_serializer_path: '%kernel.cache_dir%/htmlpurifier'
68+
html_profiles:
69+
custom:
70+
config:
71+
Core.Encoding: 'ISO-8859-1'
7272
```
7373

7474
In this example, a `exercise_html_purifier.custom` service will also be defined,
@@ -81,7 +81,7 @@ option to suppress the default path.
8181

8282
[configuration documentation]: http://htmlpurifier.org/live/configdoc/plain.html
8383

84-
## Configuration using Symfony Flex
84+
## Configuration in Symfony 4 and up
8585

8686
If you do not explicitly configure this bundle, an HTMLPurifier service will be
8787
defined as `exercise_html_purifier.default`. This behavior is the same as if you
@@ -91,8 +91,7 @@ had specified the following configuration:
9191
# config/packages/exercise_html_purifier.yaml
9292
9393
exercise_html_purifier:
94-
default:
95-
Cache.SerializerPath: '%kernel.cache_dir%/htmlpurifier'
94+
default_cache_serializer_path: '%kernel.cache_dir%/htmlpurifier'
9695
```
9796

9897
The `default` profile is special, it is *always* defined and its configuration
@@ -104,27 +103,33 @@ configuration.
104103
# config/packages/exercise_html_purifier.yaml
105104
106105
exercise_html_purifier:
107-
default:
108-
Cache.SerializerPath: '%kernel.cache_dir%/htmlpurifier'
109-
custom:
110-
Core.Encoding: 'ISO-8859-1'
106+
default_cache_serializer_path: 'tmp/htmlpurifier'
107+
html_profiles:
108+
default:
109+
config:
110+
Cache.SerializerPermissions: 777
111+
custom:
112+
config:
113+
Core.Encoding: 'ISO-8859-1'
111114
```
112-
115+
113116
## Autowiring
114117

115118
By default type hinting `\HtmlPurifier` in your services will autowire
116119
the `exercise_html_purifier.default` service.
117120
To override it and use your own config as default autowired services just add
118-
this in you `app/config/services.yml` or `config/services.yaml`:
121+
this in you `app/config/services.yml` in you use symfony 3 or `config/services.yaml`
122+
if you use symfony 4:
119123

120124
```yaml
125+
# config/services.yaml
121126
services:
122-
# ...
123-
127+
#...
128+
124129
exercise_html_purifier.default: '@exercise_html_purifier.custom'
125130
```
126131

127-
## Using a custom purifier class as default
132+
### Using a custom purifier class as default
128133

129134
If you want to use your own class as default purifier, define a new alias:
130135

@@ -139,6 +144,29 @@ services:
139144
In such case, the custom purifier will use its own defined configuration,
140145
ignoring the bundle configuration.
141146

147+
### Argument binding
148+
149+
The bundle also leverages the alias argument binding for each profile. So the
150+
following config:
151+
152+
```yaml
153+
html_profiles:
154+
blog:
155+
# ...
156+
gallery:
157+
# ...
158+
```
159+
160+
will register the following binding:
161+
162+
```php
163+
// default config is bound whichever argument name is used
164+
public function __construct(\HTMLPurifier $purifier) {}
165+
public function __construct(\HTMLPurifier $htmlPurifier) {}
166+
public function __construct(\HTMLPurifier $blogPurifier) {} // blog config
167+
public function __construct(\HTMLPurifier $galleryPurifier) {} // gallery config
168+
```
169+
142170
## Form Type Extension
143171

144172
This bundles provides a form type extension for filtering form fields with
@@ -229,6 +257,128 @@ $builder
229257
{{ html_string|purify('custom') }}
230258
```
231259

260+
## How to Customize a Config Definition
261+
262+
# Custom Attributes
263+
264+
In some case, you might want to set some rules for a specific tag.
265+
This is what the following config is about:
266+
267+
```yaml
268+
# config/packages/exercise_html_purifier.yaml
269+
exercise_html_purifier:
270+
html_profiles:
271+
default:
272+
config:
273+
HTML.Allowed: <
274+
*[id|class|name],
275+
a[href|title|rel|target],
276+
img[src|alt|height|width],
277+
br,div,embed,object,u,em,ul,ol,li,strong,span
278+
attributes:
279+
img:
280+
# attribute name, type (Integer, Color, ...)
281+
data-id: ID
282+
data-image-size: Text
283+
span:
284+
data-link: URI
285+
```
286+
287+
See [HTMLPurifier_AttrTypes][] for more options.
288+
289+
[HTMLPurifier_AttrTypes]: https://github.com/ezyang/htmlpurifier/blob/master/library/HTMLPurifier/AttrTypes.php
290+
291+
# Custom Elements
292+
293+
In some case, you might want to set some rules for a specific tag.
294+
This is what the following config is about:
295+
296+
```yaml
297+
# config/packages/exercise_html_purifier.yaml
298+
exercise_html_purifier:
299+
html_profiles:
300+
default:
301+
# ...
302+
elements:
303+
video:
304+
- Block
305+
- 'Optional: (source, Flow) | (Flow, source) | Flow'
306+
- Common # allows a set of common attributes
307+
# The 4th and 5th arguments are optional
308+
- src: URI # list of type rules by attributes
309+
type: Text
310+
width: Length
311+
height: Length
312+
poster: URI
313+
preload: 'Enum#auto,metadata,none'
314+
controls: Bool
315+
source:
316+
- Block
317+
- Flow
318+
- Common
319+
- { src: URI, type: Text }
320+
- [style] # list of forbidden attributes
321+
```
322+
323+
Would be equivalent to:
324+
325+
```php
326+
$def = $config->getHTMLDefintion(true);
327+
$def->addElement('video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [
328+
'src' => 'URI',
329+
'type' => 'Text',
330+
'width' => 'Length',
331+
'height' => 'Length',
332+
'poster' => 'URI',
333+
'preload' => 'Enum#auto,metadata,none',
334+
'controls' => 'Bool',
335+
]);
336+
$source = $def->addElement('source', 'Block', 'Flow', 'Common', [
337+
'src' => 'URI',
338+
'type' => 'Text',
339+
]);
340+
$source->excludes = ['style' => true];
341+
```
342+
343+
See [HTMLPurifier documentation][] for more details.
344+
345+
[HTMLPurifier documentation]: http://htmlpurifier.org/docs/enduser-customize.html
346+
347+
# Blank Elements
348+
349+
It might happen that you need a tag clean from any attributes.
350+
Then just add it to the list:
351+
352+
```yaml
353+
# config/packages/exercise_html_purifier.yaml
354+
exercise_html_purifier:
355+
html_profiles:
356+
default:
357+
# ...
358+
blank_elements: [legend, figcaption]
359+
```
360+
361+
## How to Reuse Profiles
362+
363+
What can really convenient is to reuse some profile definition
364+
to build other custom definitions.
365+
366+
```yaml
367+
# config/packages/exercise_html_purifier.yaml
368+
exercise_html_purifier:
369+
html_profiles:
370+
base:
371+
# ...
372+
video:
373+
# ...
374+
all:
375+
parents: [base, video]
376+
```
377+
378+
In this example the profile named "all" will inherit the "default" profile,
379+
then the two custom ones. The order is important as each profile overrides the
380+
previous, and "all" could define its own rules too.
381+
232382
## Contributing
233383

234384
PRs are welcomed :). Please target the `2.0` branch for bug fixes and `master`
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Exercise\HTMLPurifierBundle\Tests;
4+
5+
use Exercise\HTMLPurifierBundle\HTMLPurifierConfigFactory;
6+
use PHPUnit\Framework\TestCase;
7+
use Symfony\Component\Filesystem\Filesystem;
8+
9+
class HTMLPurifierConfigFactoryTest extends TestCase
10+
{
11+
private static $cacheDir;
12+
13+
public static function setUpBeforeClass(): void
14+
{
15+
self::$cacheDir = sys_get_temp_dir().DIRECTORY_SEPARATOR.'html_purifier';
16+
(new Filesystem())->mkdir(self::$cacheDir);
17+
}
18+
19+
public static function tearDownAfterClass(): void
20+
{
21+
(new Filesystem())->remove(self::$cacheDir);
22+
}
23+
24+
public function testCreateUseDoesNotBuildDefinitionByDefault()
25+
{
26+
TestHTMLPurifierConfigFactory::create('default', []);
27+
28+
$this->assertSame(0, TestHTMLPurifierConfigFactory::$calledBuild);
29+
}
30+
31+
public function testCreateUseSerializedCache()
32+
{
33+
$configArgs = [
34+
'test', /* profile */
35+
[/* config array */
36+
'Cache.SerializerPath' => self::$cacheDir,
37+
'HTML.Nofollow' => true,
38+
],
39+
null, /* default config */
40+
[], /* parents */
41+
['a' => ['href' => 'URI']], /* attributes */
42+
];
43+
44+
(new \HTMLPurifier(
45+
TestHTMLPurifierConfigFactory::create(...$configArgs)
46+
))->purify('<div>test</div>');
47+
48+
TestHTMLPurifierConfigFactory::create(...$configArgs);
49+
50+
$this->assertSame(1, TestHTMLPurifierConfigFactory::$calledBuild);
51+
}
52+
}
53+
54+
class TestHTMLPurifierConfigFactory extends HTMLPurifierConfigFactory
55+
{
56+
public static $calledBuild = 0;
57+
58+
public static function buildHTMLDefinition(
59+
\HTMLPurifier_Definition $def,
60+
array $attributes,
61+
array $elements,
62+
array $blankElements
63+
): void {
64+
++self::$calledBuild;
65+
parent::buildHTMLDefinition($def, $attributes, $elements, $blankElements);
66+
}
67+
}

0 commit comments

Comments
 (0)