Prepare for v2#46
Conversation
|
Sorry for the noise I wanted to open a PR on my own fork to test the support of some Symfony 4 projects needing this dependency. Thank you. |
|
And btw if you're still interested in maintaining this bundle and any feature in there I would be glad to open a proper PR and add a BC layer if needed. |
|
@HeahDude we need to made some branch for that. Please make PR to 4.0 branch |
|
:) So what do you need? I just remove the file headers and submit it? |
|
Yep |
|
Please check the tests locally after update - it must be green |
|
Should be good now. |
|
@HeahDude many thanks for your contribution, I'll review you PR and let you know about results |
|
With pleasure :) I'm not sure about the Symfony 2 compatibility, I have no project to test that right now. |
|
It should be tested with symfony from composer.json |
|
I confirm tests pass when forcing Symfony 2 requirements. |
|
I fixed a few things about class name convention, some typos here and there, and enforced lazy loading while keeping BC with Symfony 2, that I had left around. A review would be very welcome :). Thanks! |
|
Please add phpunit as dev dependency to composer.json, and check that tests is passed |
|
This is the case. |
|
I've removed a form option about dynamic configs that do not play well with cache. I've opened https://github.com/heahprod/HTMLPurifierBundle/pull/2 separately to ease the review but it should be merge before release as it breaks BC. It fixes #22 with custom profiles and #26. Support for Symfony 2 has been drop to ease the code and rely on powerful features. So we should merge #44 to keep BC and full support of 0.2.x versions with Symfony 3.4 and 4. I've updated the description. |
nicolas-grekas
left a comment
There was a problem hiding this comment.
I would recommend to not bump PHP to 7.1 because it would prevent Symfony 3.4+PHP 5 users from using the bundle.
| $locator = $container->getDefinition('exercise_html_purifier.purifiers_locator'); | ||
|
|
||
| foreach ($container->findTaggedServiceIds('exercise.html_purifier') as $id => $tags) { | ||
| foreach ($tags as $tag) { |
| private $cachedListeners; | ||
| private $purifiersRegistry; | ||
|
|
||
| public function __construct(HTMLPurifiersRegistry $registry) |
There was a problem hiding this comment.
the type hint should be against an interface
|
|
||
| $purifiers = []; | ||
| $purifiersLocator = $container | ||
| ->register('exercise_html_purifier.purifiers_locator', ServiceLocator::class) |
There was a problem hiding this comment.
you should use ServiceLocatorTagPass::register() instead (with 3rd arg)
| { | ||
| private $purifier; | ||
|
|
||
| public function __construct(\HTMLPurifier $purifier) |
There was a problem hiding this comment.
this should be lazy: inject two args: a registry + $profile
|
Thanks @nicolas-grekas for review! |
|
It this PR ready to be merged? It's one of the last things preventing a symfony 4 upgrade for us. Is there any way I can help out? |
|
@yakobe can you try it manually and prove that it's works? |
|
I've tested #44 with a Composer repository stanza (it works as expected, and the public service works), but I think that this PR does too much. If there was one PR to 'make this work with Symfony 4' (ie: only to make the service public), I'd take another look at it, and then I'd also look at other PRs for the additional functionality. |
| $container->setAlias('exercise_html_purifier.'.$tags[0]['profile'], $id); | ||
| } | ||
|
|
||
| $locator->setArguments($purifiers); |
There was a problem hiding this comment.
altering a ServiceLocator service is a bad idea, as the ServiceLocatorPass performs de-duplication of the service locators based on their config. You should rather ask the ServiceLocatorPass to register the service locator for the new set of arguments (or even better, configure the service locator only here in the compiler pass instead of doing it first in the DI extension and then here to find additional profiles)
| private function getHTMLPurifierListener($profile) | ||
| { | ||
| if (isset($this->cachedListeners[$profile])) { | ||
| return $this->cachedListeners[$profile]; |
There was a problem hiding this comment.
this caching is useless IMO. The instantiation of the listener is cheap, and such memoization can lead to memory leaks in long-running processes.
| */ | ||
| private function getPurifier() | ||
| { | ||
| if (null !== $this->cachedPurifier) { |
There was a problem hiding this comment.
this memoization is not worth it IMO
| #... | ||
|
|
||
| exercise_html_purifier.custom: | ||
| alias: \HTMLPurifier |
There was a problem hiding this comment.
that broken. You need to configure a HTMLPurifier alias targetting exercise_html_purifier.custom, not the opposite
There was a problem hiding this comment.
Fixed, plus added alternative syntax.
| } | ||
|
|
||
| $container->setParameter('exercise_html_purifier.cache_warmer.serializer.paths', array_unique($paths)); | ||
| $container->register(HTMLPurifiersRegistry::class) |
There was a problem hiding this comment.
the registry should not be registered using its class name, but using an id instead. We don't want the HTMLPurifiersRegistry to be available for autowiring, only the interface.
| <argument>%exercise_html_purifier.cache_warmer.serializer.paths%</argument> | ||
| <argument type="service" id="exercise_html_purifier.default" /> | ||
| <tag name="kernel.cache_warmer" /> | ||
| <defaults public="false" autowire="true" autoconfigure="true" /> |
There was a problem hiding this comment.
For shared bundles, using explicit configuration (rather than autowiring and autoconfiguration) is better, as it ensures that the bundle maintainer knows how the bundle gets configured.
Why removing the data transformer ? This is a good way to perform HTML filtering. |
|
@HeahDude Any updates on this PR? |
|
@XWB updated :). @stof Thank you very much for the review.
No... definitely not, the transformer is a wrong usage. Implementing the interface means changing the representation, one way to another. As long as an implementation cannot verify: // Given $a
$b = $transformer->transform($a);
$a === $transformer->reverseTransform($b); // must be truethen this is either wrong or a hack (even if we hack Symfony, though I'm very confident I'll get rid of that for 5.0). A view transformer is called three times in a submission process by the way. Here we just want to normalize the submitted data, we don't want to alter model or norm data in any way. Another reason is that now the purify option superseed the default trim processing. Anyone to test/review it? Thanks! |
|
https://github.com/heahprod/HTMLPurifierBundle/pull/2 has been rebased and fixed too. |
|
@stof Can you have a look as well? |
| ->setPublic(false) | ||
| ; | ||
| $container->setAlias(HTMLPurifiersRegistryInterface::class, 'exercise_html_purifier.purifiers_registry'); | ||
| $container->setAlias(\HTMLPurifier::class, 'exercise_html_purifier.default'); |
There was a problem hiding this comment.
autoloading aliases should always be private
| return $this->purifiersLocator->get($profile); | ||
| } | ||
|
|
||
| throw new \InvalidArgumentException(sprintf('The profile "%s" is not registered.', $profile)); |
There was a problem hiding this comment.
if you let $this->purifiersLocator->get trigger an exception instead, it might suggest alternative names.
There was a problem hiding this comment.
Ha, didn't know that thanks. Fixed.
| [configuration documentation]: http://htmlpurifier.org/live/configdoc/plain.html | ||
|
|
||
| ## Cache Warming ## | ||
| ## Configuration in Symfony 4 |
There was a problem hiding this comment.
isn't this exactly the same than for Symfony 3, except for the path to the YAML file, which is not actually related to 3 vs 4 but to Flex vs non-Flex (you can use Flex with 3.4)
|
|
||
| ## Purifiers Registry | ||
|
|
||
| A `Heah\HtmlPurifierBundle\HtmlPurifiersRegistry` class is registered by default |
There was a problem hiding this comment.
Good catch! Fixed.
|
|
||
| class HTMLPurifierRuntime implements RuntimeExtensionInterface | ||
| { | ||
| private $purifiersRegistry = []; |
There was a problem hiding this comment.
initializing it to an empty array is wrong. This variable is not meant to contain an array
There was a problem hiding this comment.
Artefact of previous refactoring, good catch again, thanks! Fixed.
| "description": "HTMLPurifier integration for your Symfony2 project", | ||
| "keywords": ["htmlpurifier"], | ||
| "description": "HTMLPurifier integration for your Symfony project", | ||
| "keywords": ["htmlpurifier", "html", "purifier", "symfony3", "symfony4"], |
There was a problem hiding this comment.
keyword should be symfony, not symfony3 or symfony4
| "twig/twig": "~1.3|~2.0" | ||
| "phpunit/phpunit": "^6.5.4", | ||
| "symfony/form": "~3.4.1 || ^4.0.1", | ||
| "twig/twig": "~1.6.5 || ~2.0" |
There was a problem hiding this comment.
runtimes are much newer than 1.6.5 IIRC. So this might be the wrong lowest bound.
There was a problem hiding this comment.
Runtime have been introduced in 1.26 twigphp/Twig@9cb6860#diff-16e3dbccf13c8c447eff98d226c5d89bR813.
But this is more about namespaces, so I changed to 1.34|2.4. Thanks for the hint.
| "php": ">=5.3.2", | ||
| "symfony/framework-bundle": "~2.0|~3.0", | ||
| "php": "^5.5.9|>=7.0.8", | ||
| "symfony/framework-bundle": "~3.4.1 || ^4.0.1", |
There was a problem hiding this comment.
does it actually depend on FrameworkBundle ? Or only on some other components ?
There was a problem hiding this comment.
Hmm, good question. I guess the http kernel could be added with the others require-dev deps for the cache warmer, keeping only the DI in the required ones. WDYT?
| "extra": { | ||
| "branch-alias": { | ||
| "dev-master": "1.0.x-dev" | ||
| "dev-master": "4.0.x-dev" |
There was a problem hiding this comment.
this change looks wrong to me. Why making it a 4.0 release ? This would be a 2.0 one at most
There was a problem hiding this comment.
A request from the maintainer in one of the first comment of this PR.
There was a problem hiding this comment.
I prefer to be consistent with symfony version
There was a problem hiding this comment.
but the bundle supports both 3.x and 4.x. So synchronized version number does not make sense. Thus, it means you restrict yourselves to do major versions every 2 years when Symfony does them, instead of doing them when you need them.
even official Symfony bundles developed in separate repos (MonologBundle, SwiftmailerBundle, MakerBundle) have separate version numbers (3.3.0, 3.2.2, 1.5.0 respectively).
|
Thanks again @stof. Comments addressed. |
|
|
||
| $purifiers = []; | ||
|
|
||
| foreach ($container->findTaggedServiceIds('exercise.html_purifier') as $id => $tags) { |
There was a problem hiding this comment.
Here (and in the error message) you could use the PURIFIER_TAG constant instead of the exercise.html_purifier string, right?
| @@ -0,0 +1,68 @@ | |||
| <?php | |||
|
@javiereguiluz All fixed, nice catch! Thank you for your review :) |
| try { | ||
| $registry = $container->findDefinition(HTMLPurifiersRegistryInterface::class); | ||
| } catch (ServiceNotFoundException $e) { | ||
| return; |
There was a problem hiding this comment.
Instead of the try/catch block, why not something like this:
if (!$container->hasDefinition(HTMLPurifiersRegistryInterface::class)) {
return;
}There was a problem hiding this comment.
There won't be any definition and the check will fail, we need to check for an alias here.
| $purifier = $container->getDefinition($id); | ||
|
|
||
| if (empty($purifier->getArguments())) { | ||
| $configId = "exercise_html_purifier.config.$profile"; |
There was a problem hiding this comment.
I'm not sure if this bundle follows Symfony style. If so, it should be 'exercise_html_purifier.config'.$profile;.
There was a problem hiding this comment.
This syntax may be used in the core, it mainly depends on the contextual readability it provides versus perf. This is more performant like this :)
| ->addMethodCall('loadArray', array($config)); | ||
| } | ||
| foreach ($configs as $name => $config) { | ||
| $configId = "exercise_html_purifier.config.$name"; |
There was a problem hiding this comment.
I'm not sure if this bundle follows Symfony style. If so, it should be 'exercise_html_purifier.config'.$name;.
| 'exercise_html_purifier.' . $name, | ||
| new Definition('%exercise_html_purifier.class%', array(new Reference($configId))) | ||
| ); | ||
| $container->register("exercise_html_purifier.$name", \HTMLPurifier::class) |
|
|
||
| class ExerciseHTMLPurifierBundle extends Bundle | ||
| { | ||
| public function build(ContainerBuilder $container) |
| $this->profile = $profile; | ||
| } | ||
|
|
||
| public function purifySubmittedData(FormEvent $event) |
There was a problem hiding this comment.
Following Symfony style here, we don't need to add : void.
| { | ||
| private $purifiersRegistry; | ||
|
|
||
| public function __construct(HTMLPurifiersRegistryInterface $registry) |
There was a problem hiding this comment.
What would be the benefit?
| $this->purifiersRegistry = $registry; | ||
| } | ||
|
|
||
| public function getExtendedType() |
There was a problem hiding this comment.
The entire class is missing @inheritdoc comments.
| { | ||
| private $purifiersLocator; | ||
|
|
||
| public function __construct(ContainerInterface $purifiersLocator) |
There was a problem hiding this comment.
which doc would be needed here ? Only duplicating the typehint would be useless
There was a problem hiding this comment.
Not sure it would be valuable here.
There was a problem hiding this comment.
I would swear Symfony did something similar. Apparently not.
|
Last comments addressed, I'll squash tomorrow. Thank you all for your reviews :). |
|
So should I make it a 2.0 before squash? ping @spolischook |
| } | ||
|
|
||
| /** | ||
| * @inheritdoc} |
|
IMO it should be 2.0, this PR supports both Symfony 3 and 4 anyway. |
|
@HeahDude as mentioned stof and XWB lets go with 2.0 version. |
|
@spolischook Would you create a 1.x branch from master so I can make master the target here? |
|
This is now ready to merge from my side. Once done I'll reopen https://github.com/heahprod/HTMLPurifierBundle/pull/2 on master in this repo. |
- Require PHP 5.5 or 7.0 and Symfony 3.4 minimum - Refactored extension and enabled autowiring - [BC Break] Removed classes parameters - [BC Break] Removed the form data transformer - added a new text form type extension with a purifier listener to purify submitted data in all text based fields, using opt-in and custom profile thanks to dedicated options - added a new "exercise.html_purifier" tag to make custom purifier implementations available as profile through form options and Twig filter - added a purifiers registry to lazy load purifiers everywhere - added a Twig HTMLPurifierRuntime for better performances - upgraded the LICENSE and README files
|
@spolischook rebased. Tests are green. Let's merge? |
|
@spolischook heahprod#2 is rebased with green tests, and ready to be open on master after merge before we can review, merge and release v2 :). |
|
Thanks @HeahDude for your contribution |
|
Thank you for merging! Here's the following #52 :). |
TODO
For other PRs:
src/folder and tests intests/