N°7177 Update pelago/emogrifier from 6.0.0 to 7.2.0

This commit is contained in:
Pierre Goiffon
2024-01-26 16:50:33 +01:00
parent 962eb08e40
commit e92b006f70
15 changed files with 318 additions and 136 deletions

View File

@@ -21,7 +21,7 @@
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "^4.14.0",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "^6.0.0",
"pelago/emogrifier": "^7.2.0",
"psr/log": "^3.0.0",
"scssphp/scssphp": "^1.10.3",
"symfony/console": "~6.4.0",

26
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1689d9d9deb53606c1d7ec6188662838",
"content-hash": "ad8759a06560693a5072a1cf4c7738a2",
"packages": [
{
"name": "apereo/phpcas",
@@ -1442,34 +1442,34 @@
},
{
"name": "pelago/emogrifier",
"version": "v6.0.0",
"version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/emogrifier.git",
"reference": "aa72d5407efac118f3896bcb995a2cba793df0ae"
"reference": "727bdf7255b51798307f17dec52ff8a91f1c7de3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/aa72d5407efac118f3896bcb995a2cba793df0ae",
"reference": "aa72d5407efac118f3896bcb995a2cba793df0ae",
"url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/727bdf7255b51798307f17dec52ff8a91f1c7de3",
"reference": "727bdf7255b51798307f17dec52ff8a91f1c7de3",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"php": "~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0",
"sabberworm/php-css-parser": "^8.3.1",
"symfony/css-selector": "^3.4.32 || ^4.4 || ^5.3 || ^6.0"
"php": "~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
"sabberworm/php-css-parser": "^8.4.0",
"symfony/css-selector": "^4.4.23 || ^5.4.0 || ^6.0.0 || ^7.0.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.3.0",
"phpunit/phpunit": "^8.5.16",
"rawr/cross-data-providers": "^2.3.0"
"php-parallel-lint/php-parallel-lint": "1.3.2",
"phpunit/phpunit": "9.6.11",
"rawr/cross-data-providers": "2.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "7.0.x-dev"
"dev-main": "8.0.x-dev"
}
},
"autoload": {
@@ -1516,7 +1516,7 @@
"issues": "https://github.com/MyIntervals/emogrifier/issues",
"source": "https://github.com/MyIntervals/emogrifier"
},
"time": "2021-09-16T16:22:04+00:00"
"time": "2023-12-06T02:00:20+00:00"
},
{
"name": "psr/cache",

View File

@@ -1496,36 +1496,36 @@
},
{
"name": "pelago/emogrifier",
"version": "v6.0.0",
"version_normalized": "6.0.0.0",
"version": "v7.2.0",
"version_normalized": "7.2.0.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/emogrifier.git",
"reference": "aa72d5407efac118f3896bcb995a2cba793df0ae"
"reference": "727bdf7255b51798307f17dec52ff8a91f1c7de3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/aa72d5407efac118f3896bcb995a2cba793df0ae",
"reference": "aa72d5407efac118f3896bcb995a2cba793df0ae",
"url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/727bdf7255b51798307f17dec52ff8a91f1c7de3",
"reference": "727bdf7255b51798307f17dec52ff8a91f1c7de3",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"php": "~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0",
"sabberworm/php-css-parser": "^8.3.1",
"symfony/css-selector": "^3.4.32 || ^4.4 || ^5.3 || ^6.0"
"php": "~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
"sabberworm/php-css-parser": "^8.4.0",
"symfony/css-selector": "^4.4.23 || ^5.4.0 || ^6.0.0 || ^7.0.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.3.0",
"phpunit/phpunit": "^8.5.16",
"rawr/cross-data-providers": "^2.3.0"
"php-parallel-lint/php-parallel-lint": "1.3.2",
"phpunit/phpunit": "9.6.11",
"rawr/cross-data-providers": "2.4.0"
},
"time": "2021-09-16T16:22:04+00:00",
"time": "2023-12-06T02:00:20+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "7.0.x-dev"
"dev-main": "8.0.x-dev"
}
},
"installation-source": "dist",

View File

@@ -3,7 +3,7 @@
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '1878aafd4399ad3109742460b5de84883ee87db2',
'reference' => 'befb061f0ddb07527ed1d1fb0dde21e29428db75',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -22,7 +22,7 @@
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '1878aafd4399ad3109742460b5de84883ee87db2',
'reference' => 'befb061f0ddb07527ed1d1fb0dde21e29428db75',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -206,9 +206,9 @@
'dev_requirement' => false,
),
'pelago/emogrifier' => array(
'pretty_version' => 'v6.0.0',
'version' => '6.0.0.0',
'reference' => 'aa72d5407efac118f3896bcb995a2cba793df0ae',
'pretty_version' => 'v7.2.0',
'version' => '7.2.0.0',
'reference' => '727bdf7255b51798307f17dec52ff8a91f1c7de3',
'type' => 'library',
'install_path' => __DIR__ . '/../pelago/emogrifier',
'aliases' => array(),

View File

@@ -10,12 +10,45 @@ This project adheres to [Semantic Versioning](https://semver.org/).
### Changed
### Deprecated
- Support for PHP 7.3 will be removed in Emogrifier 8.0.
### Removed
### Fixed
## 7.2.0: Add support for Symfony 7
### Added
- Add support for Symfony 7 (#1243)
## 7.1.0: Add support for PHP 8.3
### Added
- Add support for PHP 8.3 (#1218)
### Changed
- Disable HTML formatting by default (#1214)
## 7.0.0
### Added
- Add support for PHP 8.2 (#1155)
### Changed
- Throw exception with invalid CSS in debug mode (#1142)
- Only support up to 69 atomic expressions in a selector (#1113)
- Require `sabberworm/php-css-parser:^8.4.0` (#1134)
- Upgrade to PHPUnit 9 (#1112)
### Deprecated
- Support for PHP 7.3 will be removed in Emogrifier 8.0.
### Removed
- Drop support for Symfony 3.x and 5.3 (#1120, #1162)
- Drop support for PHP 7.2 (#1111)
### Fixed
- Bump the minimum Symfony 4.4 version to avoid PHP deprecation warnings (#1187)
## 6.0.0
### Added

View File

@@ -3,7 +3,6 @@
[![Build Status](https://github.com/MyIntervals/emogrifier/workflows/CI/badge.svg?branch=main)](https://github.com/MyIntervals/emogrifier/actions/)
[![Latest Stable Version](https://poser.pugx.org/pelago/emogrifier/v/stable.svg)](https://packagist.org/packages/pelago/emogrifier)
[![Total Downloads](https://poser.pugx.org/pelago/emogrifier/downloads.svg)](https://packagist.org/packages/pelago/emogrifier)
[![Latest Unstable Version](https://poser.pugx.org/pelago/emogrifier/v/unstable.svg)](https://packagist.org/packages/pelago/emogrifier)
[![License](https://poser.pugx.org/pelago/emogrifier/license.svg)](https://packagist.org/packages/pelago/emogrifier)
_n. e•mog•ri•fi•er [\ē-'mä-grƏ-,fī-Ər\] - a utility for changing completely the
@@ -122,7 +121,6 @@ The `HtmlNormalizer` class normalizes the given HTML in the following ways:
- add a document type (HTML5) if missing
- disentangle incorrectly nested tags
- add HEAD and BODY elements (if they are missing)
- reformat the HTML
The class can be used like this:
@@ -408,16 +406,16 @@ They will, however, be preserved and copied to a `<style>` element in the HTML:
1. In the [composer.json](composer.json), update the `branch-alias` entry to
point to the release _after_ the upcoming release.
1. In the [CHANGELOG.md](CHANGELOG.md), create a new section with subheadings
2. In the [CHANGELOG.md](CHANGELOG.md), create a new section with subheadings
for changes _after_ the upcoming release, set the version number for the
upcoming release, and remove any empty sections.
1. Create a pull request "Prepare release of version x.y.z" with those
3. Create a pull request "Prepare release of version x.y.z" with those
changes.
1. Have the pull request reviewed and merged.
1. Tag the new release.
1. In the [Releases tab](https://github.com/MyIntervals/emogrifier/releases),
4. Have the pull request reviewed and merged.
5. Tag the new release.
6. In the [Releases tab](https://github.com/MyIntervals/emogrifier/releases),
create a new release and copy the change log entries to the new release.
1. Post about the new release on social media.
7. Post about the new release on social media.
## Maintainers

View File

@@ -1,13 +1,12 @@
{
"name": "pelago/emogrifier",
"description": "Converts CSS styles into inline style attributes in your HTML code",
"license": "MIT",
"keywords": [
"email",
"css",
"pre-processing"
],
"homepage": "https://www.myintervals.com/emogrifier.php",
"license": "MIT",
"authors": [
{
"name": "Oliver Klee",
@@ -32,29 +31,24 @@
"name": "Jaime Prado"
}
],
"homepage": "https://www.myintervals.com/emogrifier.php",
"support": {
"issues": "https://github.com/MyIntervals/emogrifier/issues",
"source": "https://github.com/MyIntervals/emogrifier"
},
"require": {
"php": "~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0",
"php": "~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
"ext-dom": "*",
"ext-libxml": "*",
"sabberworm/php-css-parser": "^8.3.1",
"symfony/css-selector": "^3.4.32 || ^4.4 || ^5.3 || ^6.0"
"sabberworm/php-css-parser": "^8.4.0",
"symfony/css-selector": "^4.4.23 || ^5.4.0 || ^6.0.0 || ^7.0.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.3.0",
"phpunit/phpunit": "^8.5.16",
"rawr/cross-data-providers": "^2.3.0"
},
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-main": "7.0.x-dev"
}
"php-parallel-lint/php-parallel-lint": "1.3.2",
"phpunit/phpunit": "9.6.11",
"rawr/cross-data-providers": "2.4.0"
},
"prefer-stable": true,
"autoload": {
"psr-4": {
"Pelago\\Emogrifier\\": "src/"
@@ -65,21 +59,31 @@
"Pelago\\Emogrifier\\Tests\\": "tests/"
}
},
"prefer-stable": true,
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-main": "8.0.x-dev"
}
},
"scripts": {
"ci": [
"@ci:static",
"@ci:dynamic"
],
"ci:composer:normalize": "@php \"./.phive/composer-normalize\" --dry-run",
"ci:composer:normalize": "\"./.phive/composer-normalize\" --dry-run",
"ci:dynamic": [
"@ci:tests"
],
"ci:php:fixer": "@php \"./.phive/php-cs-fixer\" --config=config/php-cs-fixer.php fix --dry-run -v --show-progress=dots config/ src/ tests/",
"ci:php:fixer": "\"./.phive/php-cs-fixer\" --config=config/php-cs-fixer.php fix --dry-run -v --show-progress=dots config/ src/ tests/",
"ci:php:lint": "\"./vendor/bin/parallel-lint\" config src tests",
"ci:php:md": "@php \"./.phive/phpmd\" src text config/phpmd.xml",
"ci:php:psalm": "@php \"./.phive/psalm\" --show-info=false",
"ci:php:sniff": "@php \"./.phive/phpcs\" config src tests",
"ci:php:md": "\"./.phive/phpmd\" src text config/phpmd.xml",
"ci:php:psalm": "\"./.phive/psalm\" --show-info=false",
"ci:php:sniff": "\"./.phive/phpcs\" config src tests",
"ci:static": [
"@ci:composer:normalize",
"@ci:php:lint",
@@ -91,13 +95,13 @@
"ci:tests": [
"@ci:tests:unit"
],
"ci:tests:sof": "@php \"./vendor/bin/phpunit\" --stop-on-failure",
"ci:tests:unit": "@php \"./vendor/bin/phpunit\"",
"composer:normalize": "@php \"./.phive/composer-normalize\"",
"php:fix": "@php \"./.phive/php-cs-fixer\" --config=config/php-cs-fixer.php fix config/ src/ tests/",
"ci:tests:sof": "@php \"./vendor/bin/phpunit\" --stop-on-failure --do-not-cache-result",
"ci:tests:unit": "@php \"./vendor/bin/phpunit\" --do-not-cache-result",
"composer:normalize": "\"./.phive/composer-normalize\" --no-check-lock",
"php:fix": "\"./.phive/php-cs-fixer\" --config=config/php-cs-fixer.php fix config/ src/ tests/",
"php:version": "@php -v | grep -Po 'PHP\\s++\\K(?:\\d++\\.)*+\\d++(?:-\\w++)?+'",
"psalm:baseline": "@php \"./.phive/psalm\" --set-baseline=psalm.baseline.xml",
"psalm:cc": "@php \"./.phive/psalm\" --clear-cache"
"psalm:baseline": "\"./.phive/psalm\" --set-baseline=psalm.baseline.xml",
"psalm:cc": "\"./.phive/psalm\" --clear-cache"
},
"scripts-descriptions": {
"ci": "Runs all dynamic and static code checks.",
@@ -117,9 +121,5 @@
"php:version": "Outputs the installed PHP version.",
"psalm:baseline": "Updates the Psalm baseline file to match the code.",
"psalm:cc": "Clears the Psalm cache."
},
"support": {
"issues": "https://github.com/MyIntervals/emogrifier/issues",
"source": "https://github.com/MyIntervals/emogrifier"
}
}

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
executionOrder="depends,defects"
forceCoversAnnotation="true"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true">
<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -13,6 +13,7 @@ use Sabberworm\CSS\Property\Import as CssImport;
use Sabberworm\CSS\Renderable as CssRenderable;
use Sabberworm\CSS\RuleSet\DeclarationBlock as CssDeclarationBlock;
use Sabberworm\CSS\RuleSet\RuleSet as CssRuleSet;
use Sabberworm\CSS\Settings as ParserSettings;
/**
* Parses and stores a CSS document from a string of CSS, and provides methods to obtain the CSS in parts or as data
@@ -37,13 +38,30 @@ class CssDocument
/**
* @param string $css
* @param bool $debug
* If this is `true`, an exception will be thrown if invalid CSS is encountered.
* Otherwise the parser will try to do the best it can.
*/
public function __construct(string $css)
public function __construct(string $css, bool $debug)
{
$cssParser = new CssParser($css);
/** @var SabberwormCssDocument $sabberwormCssDocument */
$sabberwormCssDocument = $cssParser->parse();
$this->sabberwormCssDocument = $sabberwormCssDocument;
// CSS Parser currently throws exception with nested at-rules (like `@media`) in strict parsing mode
$parserSettings = ParserSettings::create()->withLenientParsing(!$debug || $this->hasNestedAtRule($css));
// CSS Parser currently throws exception with non-empty whitespace-only CSS in strict parsing mode, so `trim()`
// @see https://github.com/sabberworm/PHP-CSS-Parser/issues/349
$this->sabberwormCssDocument = (new CssParser(\trim($css), $parserSettings))->parse();
}
/**
* Tests if a string of CSS appears to contain an at-rule with nested rules
* (`@media`, `@supports`, `@keyframes`, `@document`,
* the latter two additionally with vendor prefixes that may commonly be used).
*
* @see https://github.com/sabberworm/PHP-CSS-Parser/issues/127
*/
private function hasNestedAtRule(string $css): bool
{
return \preg_match('/@(?:media|supports|(?:-webkit-|-moz-|-ms-|-o-)?+(keyframes|document))\\b/', $css) === 1;
}
/**
@@ -51,7 +69,7 @@ class CssDocument
*
* @param array<array-key, string> $allowedMediaTypes
*
* @return array<int, StyleRule>
* @return list<StyleRule>
*/
public function getStyleRulesData(array $allowedMediaTypes): array
{
@@ -86,7 +104,6 @@ class CssDocument
public function renderNonConditionalAtRules(): string
{
$this->isImportRuleAllowed = true;
/** @var array<int, CssRenderable> $cssContents */
$cssContents = $this->sabberwormCssDocument->getContents();
$atRules = \array_filter($cssContents, [$this, 'isValidAtRuleToRender']);
@@ -97,9 +114,7 @@ class CssDocument
$atRulesDocument = new SabberwormCssDocument();
$atRulesDocument->setContents($atRules);
/** @var string $renderedRules */
$renderedRules = $atRulesDocument->render();
return $renderedRules;
return $atRulesDocument->render();
}
/**
@@ -115,7 +130,6 @@ class CssDocument
$result = null;
if ($rule->atRuleName() === 'media') {
/** @var string $mediaQueryList */
$mediaQueryList = $rule->atRuleArgs();
[$mediaType] = \explode('(', $mediaQueryList, 2);
if (\trim($mediaType) !== '') {

View File

@@ -161,7 +161,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* @param string $css the CSS to inline, must be UTF-8-encoded
*
* @return self fluent interface
* @return $this
*
* @throws ParseException in debug mode, if an invalid selector is encountered
* @throws \RuntimeException in debug mode, if an internal PCRE error occurs
@@ -179,7 +179,7 @@ class CssInliner extends AbstractHtmlProcessor
if ($this->isStyleBlocksParsingEnabled) {
$combinedCss .= $this->getCssFromAllStyleNodes();
}
$parsedCss = new CssDocument($combinedCss);
$parsedCss = new CssDocument($combinedCss, $this->debug);
$excludedNodes = $this->getNodesToExclude();
$cssRules = $this->collateCssRules($parsedCss);
@@ -218,7 +218,7 @@ class CssInliner extends AbstractHtmlProcessor
/**
* Disables the parsing of inline styles.
*
* @return self fluent interface
* @return $this
*/
public function disableInlineStyleAttributesParsing(): self
{
@@ -230,7 +230,7 @@ class CssInliner extends AbstractHtmlProcessor
/**
* Disables the parsing of `<style>` blocks.
*
* @return self fluent interface
* @return $this
*/
public function disableStyleBlocksParsing(): self
{
@@ -244,7 +244,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* @param string $mediaName the media type name, e.g., "braille"
*
* @return self fluent interface
* @return $this
*/
public function addAllowedMediaType(string $mediaName): self
{
@@ -258,7 +258,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* @param string $mediaName the tag name, e.g., "braille"
*
* @return self fluent interface
* @return $this
*/
public function removeAllowedMediaType(string $mediaName): self
{
@@ -276,7 +276,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* @param string $selector the selector to exclude, e.g., ".editor"
*
* @return self fluent interface
* @return $this
*/
public function addExcludedSelector(string $selector): self
{
@@ -290,7 +290,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* @param string $selector the selector to no longer exclude, e.g., ".editor"
*
* @return self fluent interface
* @return $this
*/
public function removeExcludedSelector(string $selector): self
{
@@ -306,7 +306,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* @param bool $debug set to true to enable debug mode
*
* @return self fluent interface
* @return $this
*/
public function setDebug(bool $debug): self
{
@@ -463,7 +463,7 @@ class CssInliner extends AbstractHtmlProcessor
$properties = [];
foreach (\preg_split('/;(?!base64|charset)/', $cssDeclarationsBlock) as $declaration) {
/** @var array<int, string> $matches */
/** @var list<string> $matches */
$matches = [];
if (!\preg_match('/^([A-Za-z\\-]+)\\s*:\\s*(.+)$/s', \trim($declaration), $matches)) {
continue;
@@ -492,7 +492,9 @@ class CssInliner extends AbstractHtmlProcessor
$css = '';
foreach ($styleNodes as $styleNode) {
if (\is_string($styleNode->nodeValue)) {
$css .= "\n\n" . $styleNode->nodeValue;
}
$parentNode = $styleNode->parentNode;
if ($parentNode instanceof \DOMNode) {
$parentNode->removeChild($styleNode);
@@ -505,7 +507,7 @@ class CssInliner extends AbstractHtmlProcessor
/**
* Find the nodes that are not to be emogrified.
*
* @return array<int, \DOMElement>
* @return list<\DOMElement>
*
* @throws ParseException
* @throws \UnexpectedValueException
@@ -608,8 +610,8 @@ class CssInliner extends AbstractHtmlProcessor
\usort(
$cssRules['inlinable'],
/**
* @param array{selector: string, line: int} $first
* @param array{selector: string, line: int} $second
* @param array{selector: string, line: int, ...} $first
* @param array{selector: string, line: int, ...} $second
*/
function (array $first, array $second): int {
return $this->sortBySelectorPrecedence($first, $second);
@@ -667,8 +669,8 @@ class CssInliner extends AbstractHtmlProcessor
}
/**
* @param array{selector: string, line: int} $first
* @param array{selector: string, line: int} $second
* @param array{selector: string, line: int, ...} $first
* @param array{selector: string, line: int, ...} $second
*
* @return int
*/
@@ -1146,7 +1148,7 @@ class CssInliner extends AbstractHtmlProcessor
*
* This method only supports strings, not arrays of strings.
*
* @param string $pattern
* @param non-empty-string $pattern
* @param string $replacement
* @param string $subject
*

View File

@@ -240,7 +240,7 @@ abstract class AbstractHtmlProcessor
{
$domDocument = new \DOMDocument();
$domDocument->strictErrorChecking = false;
$domDocument->formatOutput = true;
$domDocument->formatOutput = false;
$libXmlState = \libxml_use_internal_errors(true);
$domDocument->loadHTML($this->prepareHtmlForDomConversion($html));
\libxml_clear_errors();

View File

@@ -50,7 +50,7 @@ class CssToAttributeConverter extends AbstractHtmlProcessor
/**
* Maps the CSS from the style nodes to visual HTML attributes.
*
* @return self fluent interface
* @return $this
*/
public function convertCssToVisualAttributes(): self
{

View File

@@ -27,7 +27,7 @@ class HtmlPruner extends AbstractHtmlProcessor
/**
* Removes elements that have a "display: none;" style.
*
* @return self fluent interface
* @return $this
*/
public function removeElementsWithDisplayNone(): self
{
@@ -57,7 +57,7 @@ class HtmlPruner extends AbstractHtmlProcessor
*
* @param array<array-key, string> $classesToKeep names of classes that should not be removed
*
* @return self fluent interface
* @return $this
*/
public function removeRedundantClasses(array $classesToKeep = []): self
{
@@ -118,7 +118,7 @@ class HtmlPruner extends AbstractHtmlProcessor
*
* @param CssInliner $cssInliner object instance that performed the CSS inlining
*
* @return self fluent interface
* @return $this
*
* @throws \BadMethodCallException if `inlineCss` has not first been called on `$cssInliner`
*/

View File

@@ -30,6 +30,7 @@ use Laminas\Mime\Part;
use Pelago\Emogrifier\CssInliner;
use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
use Symfony\Component\CssSelector\Exception\ParseException;
class EMailLaminas extends Email
{
@@ -415,10 +416,8 @@ class EMailLaminas extends Email
$oBody = new \Laminas\Mime\Message();
$aAdditionalParts = [];
if (($sMimeType === Mime::TYPE_HTML) && ($sCustomStyles !== null)) {
$oDomDocument = CssInliner::fromHtml($sBody)->inlineCss($sCustomStyles)->getDomDocument();
HtmlPruner::fromDomDocument($oDomDocument)->removeElementsWithDisplayNone();
$sBody = CssToAttributeConverter::fromDomDocument($oDomDocument)->convertCssToVisualAttributes()->render(); // Adds html/body tags if not already present
if ($sMimeType === Mime::TYPE_HTML) {
$sBody = static::InlineCssIntoBodyContent($sBody, $sCustomStyles);
}
$this->m_aData['body'] = array('body' => $sBody, 'mimeType' => $sMimeType);
@@ -618,4 +617,25 @@ class EMailLaminas extends Email
}
}
/**
* @param string $sBody
* @param string $sCustomStyles
*
* @return string
* @throws \Symfony\Component\CssSelector\Exception\ParseException
* @noinspection PhpUnnecessaryLocalVariableInspection
*/
protected static function InlineCssIntoBodyContent($sBody, $sCustomStyles): string
{
if (is_null($sCustomStyles)) {
return $sBody;
}
$oDomDocument = CssInliner::fromHtml($sBody)->inlineCss($sCustomStyles)->getDomDocument();
HtmlPruner::fromDomDocument($oDomDocument)->removeElementsWithDisplayNone();
$sBody = CssToAttributeConverter::fromDomDocument($oDomDocument)->convertCssToVisualAttributes()->render(); // Adds html/body tags if not already present
return $sBody;
}
}

View File

@@ -0,0 +1,138 @@
<?php
use Combodo\iTop\Test\UnitTest\ItopTestCase;
class EmailLaminasTest extends ItopTestCase
{
public function testInlineCssIntoBodyContent(): void
{
$sInputBody = <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>Hello Claude Monet</p>
<p>&nbsp;</p>
<p>The ticket R-000041 had been created</p>
<p>&nbsp;</p>
<p>Public_log:</p>
<p></p>
<table style="width: 100%; table-layout: fixed;"><tr><td>
<div class="caselog_header">
<span class="caselog_header_date">2020-05-06 17:53:23</span> - <span class="caselog_header_user">Marguerite Duras</span>:</div>
<div class="caselog_entry_html" style="">
<p>This is a test</p>
<p>in the public log</p>
</div>
</td></tr></table><p>&nbsp;</p>
<p>Impacted CI:</p>
<p></p>
<ul><li>Apache VM1</li>
<li>Open ERP</li>
<li>ERP</li>
<li>Sales web site</li>
<li>Sugar CRM</li>
<li>CRM</li>
<li>itop</li>
</ul><p>&nbsp;</p>
<p>You can communicate and followup on <span class="object-ref " title="User Request::38"><a class="object-ref-link" href="http://192.168.56.104/itop-demo/pages/exec.php/object/edit/UserRequest/38?exec_module=itop-portal-base&amp;exec_page=index.php&amp;exec_env=production&amp;portal_id=itop-portal">R-000041</a></span></p>
<p>&nbsp;</p>
<p>Regards</p>
<p><strong>The IT Team</strong></p>
</body>
</html>
HTML;
$sInputCss = <<<CSS
.caselog_header {
padding: 3px;
border-top: 1px solid #fff;
background-color: #ddd;
padding-left: 16px;
width: 100%;
}
.caselog_header_date {
}
.caselog_header_user {
}
body {
background-color: red;
}
CSS;
$sExpectedBody = <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="background-color: red;" bgcolor="red">
<p>Hello Claude Monet</p>
<p> </p>
<p>The ticket R-000041 had been created</p>
<p> </p>
<p>Public_log:</p>
<p></p>
<table style="width: 100%; table-layout: fixed;" width="100%"><tr><td>
<div class="caselog_header" style="padding: 3px; border-top: 1px solid #fff; background-color: #ddd; padding-left: 16px; width: 100%;" bgcolor="#ddd" width="100%">
<span class="caselog_header_date">2020-05-06 17:53:23</span> - <span class="caselog_header_user">Marguerite Duras</span>:</div>
<div class="caselog_entry_html" style="">
<p>This is a test</p>
<p>in the public log</p>
</div>
</td></tr></table><p> </p>
<p>Impacted CI:</p>
<p></p>
<ul><li>Apache VM1</li>
<li>Open ERP</li>
<li>ERP</li>
<li>Sales web site</li>
<li>Sugar CRM</li>
<li>CRM</li>
<li>itop</li>
</ul><p> </p>
<p>You can communicate and followup on <span class="object-ref " title="User Request::38"><a class="object-ref-link" href="http://192.168.56.104/itop-demo/pages/exec.php/object/edit/UserRequest/38?exec_module=itop-portal-base&amp;exec_page=index.php&amp;exec_env=production&amp;portal_id=itop-portal">R-000041</a></span></p>
<p> </p>
<p>Regards</p>
<p><strong>The IT Team</strong></p>
</body>
</html>
HTML;
$sExpectedBody .= "\n"; // Emogriffer is always adding latest line feed, adding it in expected content !
$sActualBody = $this->InvokeNonPublicStaticMethod(EMailLaminas::class, 'InlineCssIntoBodyContent', [$sInputBody, $sInputCss]);
$this->assertSame($sExpectedBody, $sActualBody);
}
}