-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Big architecture rework #994
Comments
I'll look into the Facade design pattern and have a think... On the topic of |
I think it certainly makes sense as a first step to move the Ultimately I think For backwards-compatibility, there could be a 'default' In the case of Thus, for public function inlineCss(string $css = ''): self
{
if (!isset($this->defaultHtmlDocument)) {
throw new \BadMethodCallException('A default HTML document has not been set');
}
$this->setCss($css);
$this->processHtmlDocument($this->defaultHtmlDocument);
return $this;
} ...where I haven't thought through how this would work for the classes that currently have multiple processing methods. An advantage of a single processing method following a defined interface is allowing HTML processors to be chained into an 'array' - which could have a class, also implementing the same interface, to manage the chaining. A likely use case would be to set up a single HTML processor (e.g. either a Some kind of wrapper (or facade?) might involve the creation of the/each |
public function processWith(HtmlProcessor $processor): self
{
$processor->processHtmlDocument($this);
return $this;
} which would allow method chaining such as $visualHtml = HtmlDocument::fromHtml($html)->processWith(new CssInliner($css))->render(); or $visualHtml = HtmlDocument::fromHtml($html)
->processWith(new HtmlProcessorArray([
new CssInliner($css),
new HtmlPruner(),
new CssToAttributeConverter(),
]))
->render(); |
To make the initial Emogrifier-provided class injectable as a service (and hence mockable in tests), the wrapper could provide an API like this: // `$emogrifier` can also get injected instead of getting instantiated.
$emogrifier = new Emogrifier();
// minimal example without additional CSS
$result = $emogrifier->inlineCss($html)->render();
// only render the body; available at all places
$result = $emogrifier->inlineCss($html)->renderBody();
// minimal example with additional CSS
$result = $emogrifier->inlineCss($html, $css)->render();
// big example with multiple HTML processors
$result = $emogrifier->inlineCss($html, $css)->disabledInlineStyleAttribuesParsing()->someOtherCssInlinerMethod()
->removeClassAttributeFromElements()
->someOtherMethodFromHtmlPruner()
->render();
// Then do the same with some other HTML.
$result2 = $emogrifier->inlineCss($html2, $css)->render();
// Split up across multiple variables
$intermediateResult = $emogrifier->inlineCss($html, $css)->disabledInlineStyleAttribuesParsing()->someOtherCssInlinerMethod()
->removeClassAttributeFromElements()
$result = $intermediateResult->someOtherMethodFromHtmlPruner()
->render(); (I'm thinking of some clever way of passing around results and executing the HTML processors lazily.) What do you think, @JakeQZ? |
I think this wouldn't be mutually exclusive with other ideas in this thread. Presubly these methods (apart from I imagine internally the
If the CSS was the same as the first time, we wouldn't want to re-parse it (so would perhaps re-use the previous
This would need lazy processing. I guess the class could internally build up a list of processing operations to perform, and only execute them when |
To weigh in from the perspective of #828. I'm not sure how far you want to go with respect to decoupling DOMDocument usage... The biggest benefit of the If you wanted to fully decouple (OO), then what Jake suggested of using an interface would be the best way to go. That interface would have to implement all the currently used methods like Happy to help if an approach is agreed upon. |
@bytestream Then please let's start with the interface and the proxy implementing it for the DOM class. Would you be willing to tackle this task? |
To clarify, I was suggesting perhaps introducing an
Or provide higher-level methods such as
Actually I don't think it will be practical to conceal the |
In addition to the small architectural problems (
CssInliner
is too big and does too much, arrays andstdClass
instead of dedicated classes), I currently see two big problems I'd like to solve:HtmlProcessor
family of classes (includingCssInliner
) currently mix two responsibilities:1.1. changing the HTML (which they should keep doing)
1.2. parsing and storing the HTML (which I'd like to move to a dedicated class (or family of classes)
The first set of problems is solvable without any (major) breaking changes, I think: We need to move stuff out to other classes. This also makes solving the second big problem easier to solve as the code then is easier understand and modify (and the risk of breaking things is reduced if we have smaller classes with clear contracts).
Maybe we can have a (new)
Emogrifier
(naming still TBD) class that wrapsCssInliner
etc. using the Facade design pattern. We still need to determine a new, clean interface on how the new class should handle multiple processors while still being able to process multiple HTML documents. Maybe we can have another intermediate class returns by the newEmogrifier
methods that holds a reference to the artifacts for a single HTML document.@JakeQZ, @jjriv, @zoliszabo What do you think?
The text was updated successfully, but these errors were encountered: