Skip to content

Commit 6072dac

Browse files
authored
Merge pull request #14 from Bynder/feature/1.1
Feature/1.1
2 parents 689d952 + ba23a00 commit 6072dac

File tree

6 files changed

+224
-131
lines changed

6 files changed

+224
-131
lines changed

.github/dependabot.yml

Lines changed: 0 additions & 8 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -87,39 +87,4 @@ jobs:
8787
run: composer install --no-progress --prefer-dist --optimize-autoloader
8888

8989
- name: Code style with PHP-CS-Fixer
90-
run: ./vendor/bin/php-cs-fixer fix --dry-run --diff
91-
92-
coverage:
93-
runs-on: ubuntu-latest
94-
steps:
95-
- name: Checkout
96-
uses: actions/checkout@v3
97-
with:
98-
fetch-depth: 0
99-
100-
- name: Setup PHP, with composer and extensions
101-
uses: shivammathur/setup-php@v2
102-
with:
103-
php-version: 8.0
104-
extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
105-
coverage: pcov
106-
107-
- name: Get composer cache directory
108-
id: composer-cache
109-
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
110-
111-
- name: Cache composer dependencies
112-
uses: actions/cache@v3
113-
with:
114-
path: ${{ steps.composer-cache.outputs.dir }}
115-
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
116-
restore-keys: ${{ runner.os }}-composer-
117-
118-
- name: Install dependencies
119-
run: composer install --no-progress --prefer-dist --optimize-autoloader
120-
121-
- name: Coverage
122-
run: |
123-
./vendor/bin/phpunit --coverage-clover coverage-clover.xml
124-
composer global require scrutinizer/ocular
125-
~/.composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage-clover.xml
90+
run: ./vendor/bin/php-cs-fixer fix --dry-run --diff

.github/workflows/github-pages.yml

Lines changed: 0 additions & 29 deletions
This file was deleted.

composer.lock

Lines changed: 19 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/PhpWord/Shared/Html.php

Lines changed: 108 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
use DOMDocument;
2222
use DOMNode;
2323
use DOMXPath;
24-
use Exception;
2524
use PhpOffice\PhpWord\Element\AbstractContainer;
2625
use PhpOffice\PhpWord\Element\Row;
2726
use PhpOffice\PhpWord\Element\Table;
27+
use PhpOffice\PhpWord\Exception\InvalidImageException;
2828
use PhpOffice\PhpWord\Settings;
2929
use PhpOffice\PhpWord\SimpleType\Jc;
3030
use PhpOffice\PhpWord\SimpleType\NumberFormat;
@@ -48,6 +48,15 @@ class Html
4848
*/
4949
protected static $css;
5050

51+
protected static $userDefinedNodeMappings = [];
52+
53+
protected static $contentTypeFileExtensionMap = [
54+
'image/svg+xml' => 'svg',
55+
'image/jpeg' => 'jpg',
56+
'image/png' => 'png',
57+
'image/gif' => 'gif',
58+
];
59+
5160
/**
5261
* Add HTML parts.
5362
*
@@ -201,39 +210,22 @@ protected static function parseNode($node, $element, $styles = [], $data = []):
201210
}
202211
}
203212

204-
// Node mapping table
205-
$nodes = [
206-
// $method $node $element $styles $data $argument1 $argument2
207-
'p' => ['Paragraph', $node, $element, $styles, null, null, null],
208-
'h1' => ['Heading', null, $element, $styles, null, 'Heading1', null],
209-
'h2' => ['Heading', null, $element, $styles, null, 'Heading2', null],
210-
'h3' => ['Heading', null, $element, $styles, null, 'Heading3', null],
211-
'h4' => ['Heading', null, $element, $styles, null, 'Heading4', null],
212-
'h5' => ['Heading', null, $element, $styles, null, 'Heading5', null],
213-
'h6' => ['Heading', null, $element, $styles, null, 'Heading6', null],
214-
'#text' => ['Text', $node, $element, $styles, null, null, null],
215-
'strong' => ['Property', null, null, $styles, null, 'bold', true],
216-
'b' => ['Property', null, null, $styles, null, 'bold', true],
217-
'em' => ['Property', null, null, $styles, null, 'italic', true],
218-
'i' => ['Property', null, null, $styles, null, 'italic', true],
219-
'u' => ['Property', null, null, $styles, null, 'underline', 'single'],
220-
'sup' => ['Property', null, null, $styles, null, 'superScript', true],
221-
'sub' => ['Property', null, null, $styles, null, 'subScript', true],
222-
'span' => ['Span', $node, null, $styles, null, null, null],
223-
'font' => ['Span', $node, null, $styles, null, null, null],
224-
'table' => ['Table', $node, $element, $styles, null, null, null],
225-
'tr' => ['Row', $node, $element, $styles, null, null, null],
226-
'td' => ['Cell', $node, $element, $styles, null, null, null],
227-
'th' => ['Cell', $node, $element, $styles, null, null, null],
228-
'ul' => ['List', $node, $element, $styles, $data, null, null],
229-
'ol' => ['List', $node, $element, $styles, $data, null, null],
230-
'li' => ['ListItem', $node, $element, $styles, $data, null, null],
231-
'img' => ['Image', $node, $element, $styles, null, null, null],
232-
'br' => ['LineBreak', null, $element, $styles, null, null, null],
233-
'a' => ['Link', $node, $element, $styles, null, null, null],
234-
'input' => ['Input', $node, $element, $styles, null, null, null],
235-
'hr' => ['HorizRule', $node, $element, $styles, null, null, null],
236-
];
213+
$nodes = self::getNodeMappingTable($node, $element, $styles, $data);
214+
array_map(
215+
function ($argumentList, $markTag) use ($node, $element, $styles, $data, &$nodes): void {
216+
$nodes[$markTag] = [
217+
0 => $argumentList['method'],
218+
1 => $argumentList['withNode'] ? $node : null,
219+
2 => $argumentList['withElement'] ? $element : null,
220+
3 => $argumentList['withStyles'] ? $styles : null,
221+
4 => $argumentList['withData'] ? $data : null,
222+
5 => $argumentList['argument1'],
223+
6 => $argumentList['argument2'],
224+
];
225+
},
226+
self::$userDefinedNodeMappings,
227+
array_keys(self::$userDefinedNodeMappings)
228+
);
237229

238230
$newElement = null;
239231
$keys = ['node', 'element', 'styles', 'data', 'argument1', 'argument2'];
@@ -249,8 +241,9 @@ protected static function parseNode($node, $element, $styles = [], $data = []):
249241
$arguments[$keys[$i]] = &$args[$i];
250242
}
251243
}
252-
$method = "parse{$method}";
253-
$newElement = call_user_func_array(['PhpOffice\PhpWord\Shared\Html', $method], array_values($arguments));
244+
245+
$method = is_string($method) ? ['PhpOffice\PhpWord\Shared\Html', "parse{$method}"] : $method;
246+
$newElement = call_user_func_array($method, array_values($arguments));
254247

255248
// Retrieve back variables from arguments
256249
foreach ($keys as $key) {
@@ -957,6 +950,17 @@ protected static function parseImage($node, $element)
957950
$tmpDir = Settings::getTempDir() . '/';
958951
$match = [];
959952
preg_match('/.+\.(\w+)$/', $src, $match);
953+
954+
if (empty($match) || !isset($match[1])) {
955+
$contentType = get_headers($src, 1)['Content-Type'];
956+
957+
if (!array_key_exists($contentType, self::$contentTypeFileExtensionMap)) {
958+
return $element->addText("Error: Could not load image: {$src}");
959+
}
960+
961+
$match[1] = self::$contentTypeFileExtensionMap[$contentType];
962+
}
963+
960964
$src = $tmpDir . uniqid() . '.' . $match[1];
961965

962966
$ifp = fopen($src, 'wb');
@@ -969,12 +973,13 @@ protected static function parseImage($node, $element)
969973
}
970974

971975
if (is_file($src)) {
972-
$newElement = $element->addImage($src, $style);
973-
} else {
974-
throw new Exception("Could not load image $originSrc");
976+
try {
977+
return $element->addImage($src, $style);
978+
} catch (InvalidImageException $ex) {
979+
}
975980
}
976981

977-
return $newElement;
982+
return $element->addText("Error: Could not load image: {$src}");
978983
}
979984

980985
/**
@@ -1155,4 +1160,67 @@ protected static function parseHorizRule($node, $element): void
11551160
// - line - that is a shape, has different behaviour
11561161
// - repeated text, e.g. underline "_", because of unpredictable line wrapping
11571162
}
1163+
1164+
/**
1165+
* Add a custom mapping for HTML tag.
1166+
*
1167+
* @param string $htmlTag
1168+
* @param bool $withNode
1169+
* @param bool $withElement
1170+
* @param bool $withStyles
1171+
* @param bool $withData
1172+
* @param string $argument1
1173+
* @param string $argument2
1174+
* @param callable|string $method
1175+
*/
1176+
public static function addUserDefinedNodeMapping($htmlTag, $withNode, $withElement, $withStyles, $withData, $argument1, $argument2, $method): void
1177+
{
1178+
$args = compact(
1179+
'withNode',
1180+
'withElement',
1181+
'withStyles',
1182+
'withData',
1183+
'argument1',
1184+
'argument2',
1185+
'method'
1186+
);
1187+
self::$userDefinedNodeMappings[$htmlTag] = $args;
1188+
}
1189+
1190+
protected static function getNodeMappingTable($node, $element, $styles, $data)
1191+
{
1192+
// Node mapping table
1193+
return [
1194+
// $method $node $element $styles $data $argument1 $argument2
1195+
'p' => ['Paragraph', $node, $element, $styles, null, null, null],
1196+
'h1' => ['Heading', null, $element, $styles, null, 'Heading1', null],
1197+
'h2' => ['Heading', null, $element, $styles, null, 'Heading2', null],
1198+
'h3' => ['Heading', null, $element, $styles, null, 'Heading3', null],
1199+
'h4' => ['Heading', null, $element, $styles, null, 'Heading4', null],
1200+
'h5' => ['Heading', null, $element, $styles, null, 'Heading5', null],
1201+
'h6' => ['Heading', null, $element, $styles, null, 'Heading6', null],
1202+
'#text' => ['Text', $node, $element, $styles, null, null, null],
1203+
'strong' => ['Property', null, null, $styles, null, 'bold', true],
1204+
'b' => ['Property', null, null, $styles, null, 'bold', true],
1205+
'em' => ['Property', null, null, $styles, null, 'italic', true],
1206+
'i' => ['Property', null, null, $styles, null, 'italic', true],
1207+
'u' => ['Property', null, null, $styles, null, 'underline', 'single'],
1208+
'sup' => ['Property', null, null, $styles, null, 'superScript', true],
1209+
'sub' => ['Property', null, null, $styles, null, 'subScript', true],
1210+
'span' => ['Span', $node, null, $styles, null, null, null],
1211+
'font' => ['Span', $node, null, $styles, null, null, null],
1212+
'table' => ['Table', $node, $element, $styles, null, null, null],
1213+
'tr' => ['Row', $node, $element, $styles, null, null, null],
1214+
'td' => ['Cell', $node, $element, $styles, null, null, null],
1215+
'th' => ['Cell', $node, $element, $styles, null, null, null],
1216+
'ul' => ['List', $node, $element, $styles, $data, null, null],
1217+
'ol' => ['List', $node, $element, $styles, $data, null, null],
1218+
'li' => ['ListItem', $node, $element, $styles, $data, null, null],
1219+
'img' => ['Image', $node, $element, $styles, null, null, null],
1220+
'br' => ['LineBreak', null, $element, $styles, null, null, null],
1221+
'a' => ['Link', $node, $element, $styles, null, null, null],
1222+
'input' => ['Input', $node, $element, $styles, null, null, null],
1223+
'hr' => ['HorizRule', $node, $element, $styles, null, null, null],
1224+
];
1225+
}
11581226
}

0 commit comments

Comments
 (0)