Skip to content

Commit 934000d

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents d6a2106 + b99230a commit 934000d

File tree

7 files changed

+202
-8
lines changed

7 files changed

+202
-8
lines changed

docs/changes/2.x/2.0.0.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
## Enhancements
66

77
- IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515)
8+
- PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642)
89

910
### Bug fixes
1011

1112
- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531)
13+
- Html Reader : Process Titles as Headings not Paragraphs [@0b10011](https://github.com/0b10011) and [@oleibman](https://github.com/oleibman) Issue [#1692](https://github.com/PHPOffice/PHPWord/issues/1692) PR [#2533](https://github.com/PHPOffice/PHPWord/pull/2533)
14+
- Generate Table Cell if Row Doesn't Have Any [@oleibman](https://github.com/oleibman) fixing [#2505](https://github.com/PHPOffice/PHPWord/issues/2505) in [#2516](https://github.com/PHPOffice/PHPWord/pull/2516)
1215
- TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545)
16+
- TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554)
1317
- bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522)
14-
1518
- 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551)
19+
- Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618)
1620

1721
### Miscellaneous
1822

docs/usage/writers.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,29 @@ $writer = IOFactory::createWriter($oPhpWord, 'PDF');
8787
$writer->save(__DIR__ . '/sample.pdf');
8888
```
8989

90+
#### Specify the PDF Renderer
91+
92+
Before PHPWord can write a PDF, you **must** specify the renderer to use and the path to it.
93+
Currently, three renderers are supported:
94+
95+
- [DomPDF](https://github.com/dompdf/dompdf)
96+
- [MPDF](https://mpdf.github.io/)
97+
- [TCPDF](https://tcpdf.org/)
98+
99+
To specify the renderer you use two static `Settings` functions:
100+
101+
- `setPdfRendererName`: This sets the name of the renderer library to use.
102+
Provide one of [`Settings`' three `PDF_` constants](https://github.com/PHPOffice/PHPWord/blob/master/src/PhpWord/Settings.php#L39-L41) to the function call.
103+
- `setPdfRendererPath`: This sets the path to the renderer library.
104+
This directory is the renderer's package directory within Composer's _vendor_ directory.
105+
106+
In the code below, you can see an example of setting MPDF as the desired PDF renderer.
107+
108+
```php
109+
Settings::setPdfRendererName(Settings::PDF_RENDERER_MPDF);
110+
Settings::setPdfRendererPath(__DIR__ . '/../vendor/mpdf/mpdf');
111+
```
112+
90113
## RTF
91114
The name of the writer is `RTF`.
92115

src/PhpWord/Shared/ZipArchive.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PclZip;
2121
use PhpOffice\PhpWord\Exception\Exception;
2222
use PhpOffice\PhpWord\Settings;
23+
use Throwable;
2324

2425
/**
2526
* ZipArchive wrapper.
@@ -162,13 +163,16 @@ public function open($filename, $flags = null)
162163
* Close the active archive.
163164
*
164165
* @return bool
165-
*
166-
* @codeCoverageIgnore Can't find any test case. Uncomment when found.
167166
*/
168167
public function close()
169168
{
170169
if (!$this->usePclzip) {
171-
if ($this->zip->close() === false) {
170+
try {
171+
$result = @$this->zip->close();
172+
} catch (Throwable $e) {
173+
$result = false;
174+
}
175+
if ($result === false) {
172176
throw new Exception("Could not close zip file {$this->filename}: ");
173177
}
174178
}

src/PhpWord/TemplateProcessor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,8 +805,8 @@ public function cloneRow($search, $numberOfClones): void
805805
*/
806806
public function deleteRow(string $search): void
807807
{
808-
if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) {
809-
$search = '${' . $search . '}';
808+
if (self::$macroOpeningChars !== substr($search, 0, 2) && self::$macroClosingChars !== substr($search, -1)) {
809+
$search = self::$macroOpeningChars . $search . self::$macroClosingChars;
810810
}
811811

812812
$tagPos = strpos($this->tempDocumentMainPart, $search);

src/PhpWord/Writer/Word2007/Element/Table.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,14 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row): void
103103
}
104104

105105
// Write cells
106-
foreach ($row->getCells() as $cell) {
107-
$this->writeCell($xmlWriter, $cell);
106+
$cells = $row->getCells();
107+
if (count($cells) === 0) {
108+
// issue 2505 - Word treats doc as corrupt if row without cell
109+
$this->writeCell($xmlWriter, new CellElement());
110+
} else {
111+
foreach ($cells as $cell) {
112+
$this->writeCell($xmlWriter, $cell);
113+
}
108114
}
109115

110116
$xmlWriter->endElement(); // w:tr

tests/PhpWordTests/TemplateProcessorTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use PhpOffice\PhpWord\PhpWord;
2626
use PhpOffice\PhpWord\Settings;
2727
use PhpOffice\PhpWord\TemplateProcessor;
28+
use Throwable;
2829
use TypeError;
2930
use ZipArchive;
3031

@@ -63,12 +64,21 @@ protected function tearDown(): void
6364
*
6465
* @covers ::__construct
6566
* @covers ::__destruct
67+
* @covers \PhpOffice\PhpWord\Shared\ZipArchive::close
6668
*/
6769
public function testTheConstruct(): void
6870
{
6971
$object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx');
7072
self::assertInstanceOf('PhpOffice\\PhpWord\\TemplateProcessor', $object);
7173
self::assertEquals([], $object->getVariables());
74+
$object->save();
75+
76+
try {
77+
$object->zip()->close();
78+
self::fail('Expected exception for double close');
79+
} catch (Throwable $e) {
80+
// nothing to do here
81+
}
7282
}
7383

7484
/**
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
/**
3+
* This file is part of PHPWord - A pure PHP library for reading and writing
4+
* word processing documents.
5+
*
6+
* PHPWord is free software distributed under the terms of the GNU Lesser
7+
* General Public License version 3 as published by the Free Software Foundation.
8+
*
9+
* For the full copyright and license information, please read the LICENSE
10+
* file that was distributed with this source code. For the full list of
11+
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
12+
*
13+
* @see https://github.com/PHPOffice/PHPWord
14+
*
15+
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace PhpOffice\PhpWordTests\Writer\Word2007\Element;
20+
21+
use PhpOffice\PhpWord\PhpWord;
22+
use PhpOffice\PhpWord\SimpleType\TblWidth;
23+
use PhpOffice\PhpWordTests\TestHelperDOCX;
24+
25+
/**
26+
* Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace.
27+
*/
28+
class TableTest extends \PHPUnit\Framework\TestCase
29+
{
30+
/**
31+
* Executed after each method of the class.
32+
*/
33+
protected function tearDown(): void
34+
{
35+
TestHelperDOCX::clear();
36+
}
37+
38+
public static function testTableNormal(): void
39+
{
40+
$phpWord = new PhpWord();
41+
$section = $phpWord->addSection();
42+
$section->addText('Before table (normal).');
43+
$table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);
44+
$row = $table->addRow();
45+
$tc = $table->addCell();
46+
$tc->addText('R1C1');
47+
$tc = $table->addCell();
48+
$tc->addText('R1C2');
49+
$row = $table->addRow();
50+
$tc = $table->addCell();
51+
$tc->addText('R2C1');
52+
$tc = $table->addCell();
53+
$tc->addText('R2C2');
54+
$row = $table->addRow();
55+
$tc = $table->addCell();
56+
$tc->addText('R3C1');
57+
$tc = $table->addCell();
58+
$tc->addText('R3C2');
59+
$section->addText('After table.');
60+
61+
$doc = TestHelperDOCX::getDocument($phpWord);
62+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'should be only 1 table');
63+
64+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]'));
65+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc'));
66+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]'));
67+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]'));
68+
69+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]'));
70+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc'));
71+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[2]'));
72+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[3]'));
73+
74+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]'));
75+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc'));
76+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[2]'));
77+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[3]'));
78+
}
79+
80+
public static function testSomeRowWithNoCells(): void
81+
{
82+
$phpWord = new PhpWord();
83+
$section = $phpWord->addSection();
84+
$section->addText('Before table (row 2 has no cells).');
85+
$table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);
86+
$row = $table->addRow();
87+
$tc = $table->addCell();
88+
$tc->addText('R1C1');
89+
$tc = $table->addCell();
90+
$tc->addText('R1C2');
91+
$row = $table->addRow();
92+
$row = $table->addRow();
93+
$tc = $table->addCell();
94+
$tc->addText('R3C1');
95+
$tc = $table->addCell();
96+
$tc->addText('R3C2');
97+
$section->addText('After table.');
98+
99+
$doc = TestHelperDOCX::getDocument($phpWord);
100+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'should be only 1 table');
101+
102+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]'));
103+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc'));
104+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]'));
105+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]'));
106+
107+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]'));
108+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc'));
109+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[2]'));
110+
111+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]'));
112+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc'));
113+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[2]'));
114+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[3]'));
115+
}
116+
117+
public static function testOnly1RowWithNoCells(): void
118+
{
119+
$phpWord = new PhpWord();
120+
$section = $phpWord->addSection();
121+
$section->addText('Before table (only 1 row and it has no cells).');
122+
$table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);
123+
$row = $table->addRow();
124+
$section->addText('After table.');
125+
126+
$doc = TestHelperDOCX::getDocument($phpWord);
127+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'only 1 table should be written');
128+
129+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]'));
130+
self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc'));
131+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]'));
132+
133+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]'));
134+
}
135+
136+
public static function testNoRows(): void
137+
{
138+
$phpWord = new PhpWord();
139+
$section = $phpWord->addSection();
140+
$section->addText('Before table (no rows therefore omitted).');
141+
$table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);
142+
$section->addText('After table.');
143+
144+
$doc = TestHelperDOCX::getDocument($phpWord);
145+
self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[1]'), 'no table should be written');
146+
}
147+
}

0 commit comments

Comments
 (0)