From bcfb3e868c0ee086b8b746bd40984b212a294c8b Mon Sep 17 00:00:00 2001
From: Gerald Buttinger
Date: Fri, 27 Nov 2015 14:30:22 +0100
Subject: [PATCH 01/53] Add methods setValuesFromArray and cloneRowFromArray to
the TemplateProcessor-class and update samples and docs accordingly
---
docs/templates-processing.rst | 16 ++++
.../Sample_37_TemplateCloneRowFromArray.php | 91 +++++++++++++++++++
src/PhpWord/TemplateProcessor.php | 34 +++++++
3 files changed, 141 insertions(+)
mode change 100644 => 100755 docs/templates-processing.rst
create mode 100755 samples/Sample_37_TemplateCloneRowFromArray.php
mode change 100644 => 100755 src/PhpWord/TemplateProcessor.php
diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst
old mode 100644
new mode 100755
index 6a65ea0d..12b65f80
--- a/docs/templates-processing.rst
+++ b/docs/templates-processing.rst
@@ -15,11 +15,27 @@ Example:
$templateProcessor->setValue('Name', 'Somebody someone');
$templateProcessor->setValue('Street', 'Coming-Undone-Street 32');
+You can also use ``TemplateProcessor::setValuesFromArray`` method to perform replacements from an array of "variable => value"-pairs.
+
+Example:
+
+.. code-block:: php
+
+ $replacements = [
+ 'Name' => 'Somebody someone',
+ 'Street' => 'Coming-Undone-Street 32'
+ ];
+ $templateProcessor = new TemplateProcessor('Template.docx');
+ $templateProcessor->setValuesFromArray($replacements);
+
It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform main document part of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``).
See ``Sample_07_TemplateCloneRow.php`` for example on how to create
multirow from a single row in a template by using ``TemplateProcessor::cloneRow``.
+See ``Sample_37_TemplateCloneRowFromArray.php`` for example on how to create
+multirow from a single row with a two-dimensional array as data-source in a template by using ``TemplateProcessor::cloneRowFromArray``.
+
See ``Sample_23_TemplateBlock.php`` for example on how to clone a block
of text using ``TemplateProcessor::cloneBlock`` and delete a block of text using
``TemplateProcessor::deleteBlock``.
diff --git a/samples/Sample_37_TemplateCloneRowFromArray.php b/samples/Sample_37_TemplateCloneRowFromArray.php
new file mode 100755
index 00000000..5abf1103
--- /dev/null
+++ b/samples/Sample_37_TemplateCloneRowFromArray.php
@@ -0,0 +1,91 @@
+ htmlspecialchars(date('l')), // On section/content
+ 'time' => htmlspecialchars(date('H:i')), // On footer
+ 'serverName' => htmlspecialchars(realpath(__DIR__)), // On header
+];
+$templateProcessor->setValuesFromArray($replacements);
+
+// Simple table
+$rows = [
+ [
+ 'rowNumber' => 1,
+ 'rowValue' => 'Sun'
+ ],
+ [
+ 'rowNumber' => 2,
+ 'rowValue' => 'Mercury'
+ ],
+ [
+ 'rowNumber' => 3,
+ 'rowValue' => 'Venus'
+ ],
+ [
+ 'rowNumber' => 4,
+ 'rowValue' => 'Earth'
+ ],
+ [
+ 'rowNumber' => 5,
+ 'rowValue' => 'Mars'
+ ],
+ [
+ 'rowNumber' => 6,
+ 'rowValue' => 'Jupiter'
+ ],
+ [
+ 'rowNumber' => 7,
+ 'rowValue' => 'Saturn'
+ ],
+ [
+ 'rowNumber' => 8,
+ 'rowValue' => 'Uranus'
+ ],
+ [
+ 'rowNumber' => 9,
+ 'rowValue' => 'Neptun'
+ ],
+ [
+ 'rowNumber' => 10,
+ 'rowValue' => 'Pluto'
+ ]
+];
+$templateProcessor->cloneRowFromArray('rowValue', $rows);
+
+// Table with a spanned cell
+$rows = [
+ [
+ 'userId' => 1,
+ 'userFirstName' => 'James',
+ 'userName' => 'Taylor',
+ 'userPhone' => '+1 428 889 773'
+ ],
+ [
+ 'userId' => 2,
+ 'userFirstName' => 'Robert',
+ 'userName' => 'Bell',
+ 'userPhone' => '+1 428 889 774'
+ ],
+ [
+ 'userId' => 3,
+ 'userFirstName' => 'Michael',
+ 'userName' => 'Ray',
+ 'userPhone' => '+1 428 889 775'
+ ]
+];
+$templateProcessor->cloneRowFromArray('userId', $rows);
+
+
+echo date('H:i:s'), ' Saving the result document...', EOL;
+$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx');
+
+echo getEndingNotes(array('Word2007' => 'docx'));
+if (!CLI) {
+ include_once 'Sample_Footer.php';
+}
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
old mode 100644
new mode 100755
index ce92bacf..654bcf8c
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -155,6 +155,20 @@ class TemplateProcessor
}
}
+ /**
+ * Set values from a one-dimensional array of "variable => value"-pairs.
+ *
+ * @param array $values
+ *
+ * @return void
+ */
+ public function setValuesFromArray($values)
+ {
+ foreach ($values as $macro => $replace) {
+ $this->setValue($macro, $replace);
+ }
+ }
+
/**
* Returns array of all variables in template.
*
@@ -234,6 +248,26 @@ class TemplateProcessor
$this->tempDocumentMainPart = $result;
}
+ /**
+ * Clone a table row and populates it's values from a two-dimensional array in a template document.
+ *
+ * @param string $search
+ * @param array $rows
+ *
+ * @return void
+ */
+ public function cloneRowFromArray($search, $rows)
+ {
+ $this->cloneRow($search, count($rows));
+
+ foreach ($rows as $rowKey => $rowData) {
+ $rowNumber = $rowKey+1;
+ foreach ($rowData as $macro => $replace) {
+ $this->setValue($macro.'#'.$rowNumber,$replace);
+ }
+ }
+ }
+
/**
* Clone a block.
*
From 71618f704d092ac32b73f5dc8ca2862946fba930 Mon Sep 17 00:00:00 2001
From: eweso <6918714+eweso@users.noreply.github.com>
Date: Fri, 30 Mar 2018 19:24:45 +0200
Subject: [PATCH 02/53] Adding setNumId method for ListItem style
By allowing to set the numId in the ListItem style manually, you can separate lists. Every ListItem with the same numId belongs to one list. This allows you to restart list counting.
---
src/PhpWord/Style/ListItem.php | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php
index 306ecff3..c8bd2101 100644
--- a/src/PhpWord/Style/ListItem.php
+++ b/src/PhpWord/Style/ListItem.php
@@ -11,7 +11,7 @@
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
- * @copyright 2010-2018 PHPWord contributors
+ * @copyright 2010-2017 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
@@ -139,6 +139,16 @@ class ListItem extends AbstractStyle
return $this->numId;
}
+ /**
+ * Set numbering Id, to force list to restart counting. Same num id means same list
+ * @param int
+ */
+ public function setNumId($numInt)
+ {
+ $this->numId = $numInt;
+ $this->getListTypeStyle();
+ }
+
/**
* Get legacy numbering definition
*
@@ -148,7 +158,12 @@ class ListItem extends AbstractStyle
private function getListTypeStyle()
{
// Check if legacy style already registered in global Style collection
- $numStyle = "PHPWordList{$this->listType}";
+ $numStyle = "PHPWordList_" . $this->listType;
+
+ if ($this->numId) {
+ $numStyle .= '_' . $this->numId;
+ }
+
if (Style::getStyle($numStyle) !== null) {
$this->setNumStyle($numStyle);
From a09e7151acd71f1681f4bf70824b12a92099c359 Mon Sep 17 00:00:00 2001
From: eweso <6918714+eweso@users.noreply.github.com>
Date: Fri, 30 Mar 2018 22:58:03 +0200
Subject: [PATCH 03/53] Update ListItem.php
---
src/PhpWord/Style/ListItem.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php
index c8bd2101..4a844e48 100644
--- a/src/PhpWord/Style/ListItem.php
+++ b/src/PhpWord/Style/ListItem.php
@@ -140,8 +140,8 @@ class ListItem extends AbstractStyle
}
/**
- * Set numbering Id, to force list to restart counting. Same num id means same list
- * @param int
+ * Set numbering Id. Same numId means same list
+ * @param mixed
*/
public function setNumId($numInt)
{
From 5741e47129b6c4c4c82af443bc120c8273c123db Mon Sep 17 00:00:00 2001
From: eweso <6918714+eweso@users.noreply.github.com>
Date: Sat, 31 Mar 2018 00:37:50 +0200
Subject: [PATCH 04/53] Update ListItem.php
---
src/PhpWord/Style/ListItem.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php
index 4a844e48..74bf3c97 100644
--- a/src/PhpWord/Style/ListItem.php
+++ b/src/PhpWord/Style/ListItem.php
@@ -141,7 +141,7 @@ class ListItem extends AbstractStyle
/**
* Set numbering Id. Same numId means same list
- * @param mixed
+ * @param mixed $numInt
*/
public function setNumId($numInt)
{
@@ -158,12 +158,12 @@ class ListItem extends AbstractStyle
private function getListTypeStyle()
{
// Check if legacy style already registered in global Style collection
- $numStyle = "PHPWordList_" . $this->listType;
-
+ $numStyle = 'PHPWordListType' . $this->listType;
+
if ($this->numId) {
- $numStyle .= '_' . $this->numId;
+ $numStyle .= 'NumId' . $this->numId;
}
-
+
if (Style::getStyle($numStyle) !== null) {
$this->setNumStyle($numStyle);
From 91ada213c525cb5a2712111e6c73d9ecd587b36a Mon Sep 17 00:00:00 2001
From: eweso <6918714+eweso@users.noreply.github.com>
Date: Sat, 31 Mar 2018 00:38:43 +0200
Subject: [PATCH 05/53] Update ListItem.php
---
src/PhpWord/Style/ListItem.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php
index 74bf3c97..4293940f 100644
--- a/src/PhpWord/Style/ListItem.php
+++ b/src/PhpWord/Style/ListItem.php
@@ -11,7 +11,7 @@
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
- * @copyright 2010-2017 PHPWord contributors
+ * @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
From 13fc647d01915891abee0ce106f910223772cf9c Mon Sep 17 00:00:00 2001
From: Maxim Bulygin
Date: Thu, 24 May 2018 17:03:35 +0300
Subject: [PATCH 06/53] html writes / setup table cell color
---
src/PhpWord/Writer/HTML/Element/Table.php | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php
index 844066f4..866ce1bf 100644
--- a/src/PhpWord/Writer/HTML/Element/Table.php
+++ b/src/PhpWord/Writer/HTML/Element/Table.php
@@ -50,6 +50,14 @@ class Table extends AbstractElement
$rowCellCount = count($rowCells);
for ($j = 0; $j < $rowCellCount; $j++) {
$cellStyle = $rowCells[$j]->getStyle();
+ $cellBgColor = $cellStyle->getBgColor();
+ $cellFgColor = null;
+ if ($cellBgColor) {
+ $r = hexdec(substr($cellBgColor, 0, 2));
+ $g = hexdec(substr($cellBgColor, 2, 2));
+ $b = hexdec(substr($cellBgColor, 4, 2));
+ $cellFgColor = (($r * 0.299 + $g * 0.587 + $b * 0.114) > 186) ? null : 'ffffff';
+ }
$cellColSpan = $cellStyle->getGridSpan();
$cellRowSpan = 1;
$cellVMerge = $cellStyle->getVMerge();
@@ -73,7 +81,9 @@ class Table extends AbstractElement
$cellTag = $tblHeader ? 'th' : 'td';
$cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : '');
$cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : '');
- $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}>" . PHP_EOL;
+ $cellBgColorAttr = (is_null($cellBgColor) ? '' : " bgcolor=\"#{$cellBgColor}\"");
+ $cellFgColorAttr = (is_null($cellFgColor) ? '' : " color=\"#{$cellFgColor}\"");
+ $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}{$cellBgColorAttr}{$cellFgColorAttr}>" . PHP_EOL;
$writer = new Container($this->parentWriter, $rowCells[$j]);
$content .= $writer->write();
if ($cellRowSpan > 1) {
From e40449e7c8691af4dbfefd43e7937acc46e8ce34 Mon Sep 17 00:00:00 2001
From: Maxim Bulygin
Date: Thu, 24 May 2018 17:40:21 +0300
Subject: [PATCH 07/53] fix variable names
---
src/PhpWord/Writer/HTML/Element/Table.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php
index 866ce1bf..2f10df41 100644
--- a/src/PhpWord/Writer/HTML/Element/Table.php
+++ b/src/PhpWord/Writer/HTML/Element/Table.php
@@ -53,10 +53,10 @@ class Table extends AbstractElement
$cellBgColor = $cellStyle->getBgColor();
$cellFgColor = null;
if ($cellBgColor) {
- $r = hexdec(substr($cellBgColor, 0, 2));
- $g = hexdec(substr($cellBgColor, 2, 2));
- $b = hexdec(substr($cellBgColor, 4, 2));
- $cellFgColor = (($r * 0.299 + $g * 0.587 + $b * 0.114) > 186) ? null : 'ffffff';
+ $red = hexdec(substr($cellBgColor, 0, 2));
+ $green = hexdec(substr($cellBgColor, 2, 2));
+ $blue = hexdec(substr($cellBgColor, 4, 2));
+ $cellFgColor = (($red * 0.299 + $green * 0.587 + $blue * 0.114) > 186) ? null : 'ffffff';
}
$cellColSpan = $cellStyle->getGridSpan();
$cellRowSpan = 1;
From c408ac5d504599f38e19111108a6719b3a5c4306 Mon Sep 17 00:00:00 2001
From: troosan
Date: Sun, 30 Dec 2018 14:14:27 +0100
Subject: [PATCH 08/53] Use embedded http server to test loading of remote
images
---
CHANGELOG.md | 9 ++
tests/PhpWord/Element/CellTest.php | 6 +-
tests/PhpWord/Element/FooterTest.php | 6 +-
tests/PhpWord/Element/HeaderTest.php | 6 +-
tests/PhpWord/Element/ImageTest.php | 9 +-
tests/PhpWord/MediaTest.php | 8 +-
tests/PhpWord/Shared/HtmlTest.php | 5 +-
tests/PhpWord/Writer/HTMLTest.php | 5 +-
tests/PhpWord/Writer/Word2007Test.php | 5 +-
tests/PhpWord/_files/images/new-php-logo.png | Bin 0 -> 10298 bytes
.../AbstractWebServerEmbeddedTest.php | 80 ++++++++++++++++++
11 files changed, 119 insertions(+), 20 deletions(-)
create mode 100644 tests/PhpWord/_files/images/new-php-logo.png
create mode 100644 tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d07c7bd..735264f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,15 @@ Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
+v0.17.0 (?? ??? 2019)
+----------------------
+### Added
+
+### Fixed
+
+### Miscelaneous
+- Use embedded http server to test loading of remote images @troosan #
+
v0.16.0 (30 dec 2018)
----------------------
### Added
diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php
index d4aaa488..7e63967a 100644
--- a/tests/PhpWord/Element/CellTest.php
+++ b/tests/PhpWord/Element/CellTest.php
@@ -17,12 +17,14 @@
namespace PhpOffice\PhpWord\Element;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
+
/**
* Test class for PhpOffice\PhpWord\Element\Cell
*
* @runTestsInSeparateProcesses
*/
-class CellTest extends \PHPUnit\Framework\TestCase
+class CellTest extends AbstractWebServerEmbeddedTest
{
/**
* New instance
@@ -165,7 +167,7 @@ class CellTest extends \PHPUnit\Framework\TestCase
public function testAddImageSectionByUrl()
{
$oCell = new Cell();
- $element = $oCell->addImage('http://php.net/images/logos/php-med-trans-light.gif');
+ $element = $oCell->addImage(self::getRemoteGifImageUrl());
$this->assertCount(1, $oCell->getElements());
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php
index 9de2487a..b1ef4677 100644
--- a/tests/PhpWord/Element/FooterTest.php
+++ b/tests/PhpWord/Element/FooterTest.php
@@ -17,12 +17,14 @@
namespace PhpOffice\PhpWord\Element;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
+
/**
* Test class for PhpOffice\PhpWord\Element\Footer
*
* @runTestsInSeparateProcesses
*/
-class FooterTest extends \PHPUnit\Framework\TestCase
+class FooterTest extends AbstractWebServerEmbeddedTest
{
/**
* New instance
@@ -116,7 +118,7 @@ class FooterTest extends \PHPUnit\Framework\TestCase
public function testAddImageByUrl()
{
$oFooter = new Footer(1);
- $element = $oFooter->addImage('http://php.net/images/logos/php-med-trans-light.gif');
+ $element = $oFooter->addImage(self::getRemoteGifImageUrl());
$this->assertCount(1, $oFooter->getElements());
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php
index e61175f1..4bbf7b74 100644
--- a/tests/PhpWord/Element/HeaderTest.php
+++ b/tests/PhpWord/Element/HeaderTest.php
@@ -17,12 +17,14 @@
namespace PhpOffice\PhpWord\Element;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
+
/**
* Test class for PhpOffice\PhpWord\Element\Header
*
* @runTestsInSeparateProcesses
*/
-class HeaderTest extends \PHPUnit\Framework\TestCase
+class HeaderTest extends AbstractWebServerEmbeddedTest
{
/**
* New instance
@@ -125,7 +127,7 @@ class HeaderTest extends \PHPUnit\Framework\TestCase
public function testAddImageByUrl()
{
$oHeader = new Header(1);
- $element = $oHeader->addImage('http://php.net/images/logos/php-med-trans-light.gif');
+ $element = $oHeader->addImage(self::getRemoteGifImageUrl());
$this->assertCount(1, $oHeader->getElements());
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php
index 747a77ac..f56d0794 100644
--- a/tests/PhpWord/Element/ImageTest.php
+++ b/tests/PhpWord/Element/ImageTest.php
@@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Element;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
use PhpOffice\PhpWord\SimpleType\Jc;
/**
@@ -24,7 +25,7 @@ use PhpOffice\PhpWord\SimpleType\Jc;
*
* @runTestsInSeparateProcesses
*/
-class ImageTest extends \PHPUnit\Framework\TestCase
+class ImageTest extends AbstractWebServerEmbeddedTest
{
/**
* New instance
@@ -131,7 +132,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase
*/
public function testUnsupportedImage()
{
- //disable ssl verification, never do this in real application, you should pass the certiciate instead!!!
+ //disable ssl verification, never do this in real application, you should pass the certificiate instead!!!
$arrContextOptions = array(
'ssl' => array(
'verify_peer' => false,
@@ -139,7 +140,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase
),
);
stream_context_set_default($arrContextOptions);
- $object = new Image('https://samples.libav.org/image-samples/RACECAR.BMP');
+ $object = new Image(self::getRemoteBmpImageUrl());
$object->getSource();
}
@@ -215,7 +216,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase
*/
public function testConstructFromGd()
{
- $source = 'http://php.net/images/logos/php-icon.png';
+ $source = self::getRemoteImageUrl();
$image = new Image($source);
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image);
diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php
index 02492016..3cf62b59 100644
--- a/tests/PhpWord/MediaTest.php
+++ b/tests/PhpWord/MediaTest.php
@@ -24,7 +24,7 @@ use PhpOffice\PhpWord\Element\Image;
*
* @runTestsInSeparateProcesses
*/
-class MediaTest extends \PHPUnit\Framework\TestCase
+class MediaTest extends AbstractWebServerEmbeddedTest
{
/**
* Get section media elements
@@ -49,7 +49,7 @@ class MediaTest extends \PHPUnit\Framework\TestCase
{
$local = __DIR__ . '/_files/images/mars.jpg';
$object = __DIR__ . '/_files/documents/sheet.xls';
- $remote = 'http://php.net/images/logos/php-med-trans-light.gif';
+ $remote = self::getRemoteImageUrl();
Media::addElement('section', 'image', $local, new Image($local));
Media::addElement('section', 'image', $local, new Image($local));
Media::addElement('section', 'image', $remote, new Image($local));
@@ -77,7 +77,7 @@ class MediaTest extends \PHPUnit\Framework\TestCase
public function testAddHeaderMediaElement()
{
$local = __DIR__ . '/_files/images/mars.jpg';
- $remote = 'http://php.net/images/logos/php-med-trans-light.gif';
+ $remote = self::getRemoteImageUrl();
Media::addElement('header1', 'image', $local, new Image($local));
Media::addElement('header1', 'image', $local, new Image($local));
Media::addElement('header1', 'image', $remote, new Image($remote));
@@ -92,7 +92,7 @@ class MediaTest extends \PHPUnit\Framework\TestCase
public function testAddFooterMediaElement()
{
$local = __DIR__ . '/_files/images/mars.jpg';
- $remote = 'http://php.net/images/logos/php-med-trans-light.gif';
+ $remote = self::getRemoteImageUrl();
Media::addElement('footer1', 'image', $local, new Image($local));
Media::addElement('footer1', 'image', $local, new Image($local));
Media::addElement('footer1', 'image', $remote, new Image($remote));
diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php
index 89292a20..2f9a4be4 100644
--- a/tests/PhpWord/Shared/HtmlTest.php
+++ b/tests/PhpWord/Shared/HtmlTest.php
@@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Shared;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
use PhpOffice\PhpWord\Element\Section;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\LineSpacingRule;
@@ -27,7 +28,7 @@ use PhpOffice\PhpWord\TestHelperDOCX;
* Test class for PhpOffice\PhpWord\Shared\Html
* @coversDefaultClass \PhpOffice\PhpWord\Shared\Html
*/
-class HtmlTest extends \PHPUnit\Framework\TestCase
+class HtmlTest extends AbstractWebServerEmbeddedTest
{
/**
* Test unit conversion functions with various numbers
@@ -487,7 +488,7 @@ class HtmlTest extends \PHPUnit\Framework\TestCase
*/
public function testParseRemoteImage()
{
- $src = 'https://phpword.readthedocs.io/en/latest/_images/phpword.png';
+ $src = self::getRemoteImageUrl();
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php
index 8868db5a..24a8bca3 100644
--- a/tests/PhpWord/Writer/HTMLTest.php
+++ b/tests/PhpWord/Writer/HTMLTest.php
@@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Writer;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\SimpleType\Jc;
@@ -26,7 +27,7 @@ use PhpOffice\PhpWord\SimpleType\Jc;
*
* @runTestsInSeparateProcesses
*/
-class HTMLTest extends \PHPUnit\Framework\TestCase
+class HTMLTest extends AbstractWebServerEmbeddedTest
{
/**
* Construct
@@ -57,7 +58,7 @@ class HTMLTest extends \PHPUnit\Framework\TestCase
{
$localImage = __DIR__ . '/../_files/images/PhpWord.png';
$archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg';
- $gdImage = 'http://php.net/images/logos/php-med-trans-light.gif';
+ $gdImage = self::getRemoteGifImageUrl();
$objectSrc = __DIR__ . '/../_files/documents/sheet.xls';
$file = __DIR__ . '/../_files/temp.html';
diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php
index 0db36fc1..563475b4 100644
--- a/tests/PhpWord/Writer/Word2007Test.php
+++ b/tests/PhpWord/Writer/Word2007Test.php
@@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Writer;
+use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\TestHelperDOCX;
@@ -26,7 +27,7 @@ use PhpOffice\PhpWord\TestHelperDOCX;
*
* @runTestsInSeparateProcesses
*/
-class Word2007Test extends \PHPUnit\Framework\TestCase
+class Word2007Test extends AbstractWebServerEmbeddedTest
{
/**
* Tear down after each test
@@ -75,7 +76,7 @@ class Word2007Test extends \PHPUnit\Framework\TestCase
public function testSave()
{
$localImage = __DIR__ . '/../_files/images/earth.jpg';
- $remoteImage = 'http://php.net/images/logos/new-php-logo.png';
+ $remoteImage = self::getRemoteGifImageUrl();
$phpWord = new PhpWord();
$phpWord->addFontStyle('Font', array('size' => 11));
$phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER));
diff --git a/tests/PhpWord/_files/images/new-php-logo.png b/tests/PhpWord/_files/images/new-php-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..6649079930716c425de2d675a0feebbe7d0a0d70
GIT binary patch
literal 10298
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
M07*qoM6N<$f)aut$N&HU
literal 0
HcmV?d00001
diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php
new file mode 100644
index 00000000..9316a9fe
--- /dev/null
+++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php
@@ -0,0 +1,80 @@
+start();
+ while (!self::$httpServer->isRunning()) {
+ usleep(1000);
+ }
+ }
+ }
+
+ public static function tearDownAfterClass()
+ {
+ if (self::isBuiltinServerSupported()) {
+ self::$httpServer->stop();
+ }
+ }
+
+ protected static function getBaseUrl()
+ {
+ return 'http://localhost:8080';
+ }
+
+ protected static function getRemoteImageUrl()
+ {
+ if (self::$httpServer) {
+ return self::getBaseUrl() . '/images/new-php-logo.png';
+ }
+
+ return 'http://php.net/images/logos/new-php-logo.png';
+ }
+
+ protected static function getRemoteGifImageUrl()
+ {
+ if (self::$httpServer) {
+ return self::getBaseUrl() . '/images/mario.gif';
+ }
+
+ return 'http://php.net/images/logos/php-med-trans-light.gif';
+ }
+
+ protected static function getRemoteBmpImageUrl()
+ {
+ if (self::$httpServer) {
+ return self::getBaseUrl() . '/images/duke_nukem.bmp';
+ }
+
+ return 'https://samples.libav.org/image-samples/RACECAR.BMP';
+ }
+
+ private static function isBuiltinServerSupported()
+ {
+ return version_compare(PHP_VERSION, '5.4.0', '>=');
+ }
+}
From f91863ed6431cb5e7eb6920385f51696951e4f9e Mon Sep 17 00:00:00 2001
From: troosan
Date: Thu, 3 Jan 2019 11:33:56 +0100
Subject: [PATCH 09/53] Add RTL aligning of tables
---
samples/Sample_36_RTL.php | 23 +++++++++++++
samples/index.php | 2 +-
src/PhpWord/Reader/Word2007/AbstractPart.php | 1 +
src/PhpWord/Style/Table.php | 32 +++++++++++++++++++
src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 +++
src/PhpWord/Writer/ODText/Style/Table.php | 1 +
src/PhpWord/Writer/Word2007/Style/Table.php | 3 ++
tests/PhpWord/Reader/Word2007/StyleTest.php | 18 +++++++++++
.../Writer/Word2007/Style/TableTest.php | 17 ++++++++++
9 files changed, 100 insertions(+), 1 deletion(-)
diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php
index 615557d7..ca93b14d 100644
--- a/samples/Sample_36_RTL.php
+++ b/samples/Sample_36_RTL.php
@@ -14,6 +14,29 @@ $textrun->addText('This is a Left to Right paragraph.');
$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END));
$textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true));
+$section->addText('Table visually presented as RTL');
+$style = array('rtl' => true, 'size' => 12);
+$tableStyle = array('borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true);
+
+$table = $section->addTable($tableStyle);
+$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER);
+$cellHEnd = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END);
+$cellVCentered = array('valign' => \PhpOffice\PhpWord\Style\Cell::VALIGN_CENTER);
+
+//Vidually bidirectinal table
+$table->addRow();
+$cell = $table->addCell(500, $cellVCentered);
+$textrun = $cell->addTextRun($cellHCentered);
+$textrun->addText('ردیف', $style);
+
+$cell = $table->addCell(11000);
+$textrun = $cell->addTextRun($cellHEnd);
+$textrun->addText('سوالات', $style);
+
+$cell = $table->addCell(500, $cellVCentered);
+$textrun = $cell->addTextRun($cellHCentered);
+$textrun->addText('بارم', $style);
+
// Save file
echo write($phpWord, basename(__FILE__, '.php'), $writers);
if (!CLI) {
diff --git a/samples/index.php b/samples/index.php
index 3dbc09ff..20b56b83 100644
--- a/samples/index.php
+++ b/samples/index.php
@@ -22,7 +22,7 @@ if (!CLI) {
Read the Docs
-Requirement check:';
diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php
index a7816b19..bb4a3a49 100644
--- a/src/PhpWord/Reader/Word2007/AbstractPart.php
+++ b/src/PhpWord/Reader/Word2007/AbstractPart.php
@@ -483,6 +483,7 @@ abstract class AbstractPart
$styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val');
}
$styleDefs['layout'] = array(self::READ_VALUE, 'w:tblLayout', 'w:type');
+ $styleDefs['bidiVisual'] = array(self::READ_TRUE, 'w:bidiVisual');
$styleDefs['cellSpacing'] = array(self::READ_VALUE, 'w:tblCellSpacing', 'w:w');
$style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php
index caf2c580..f777ac67 100644
--- a/src/PhpWord/Style/Table.php
+++ b/src/PhpWord/Style/Table.php
@@ -170,6 +170,14 @@ class Table extends Border
*/
private $columnWidths;
+ /**
+ * Visually Right to Left Table
+ *
+ * @see http://www.datypic.com/sc/ooxml/e-w_bidiVisual-1.html
+ * @var bool
+ */
+ private $bidiVisual = false;
+
/**
* Create new table style
*
@@ -775,4 +783,28 @@ class Table extends Border
{
$this->columnWidths = $value;
}
+
+ /**
+ * Get bidiVisual
+ *
+ * @return bool
+ */
+ public function isBidiVisual()
+ {
+ return $this->bidiVisual;
+ }
+
+ /**
+ * Set bidiVisual
+ *
+ * @param bool $bidi
+ * Set to true to visually present table as Right to Left
+ * @return self
+ */
+ public function setBidiVisual($bidi)
+ {
+ $this->bidiVisual = $bidi;
+
+ return $this;
+ }
}
diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php
index 223d02f0..f247dcc1 100644
--- a/src/PhpWord/Writer/ODText/Style/Paragraph.php
+++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php
@@ -54,6 +54,10 @@ class Paragraph extends AbstractStyle
$xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm');
$xmlWriter->writeAttribute('fo:text-align', $style->getAlignment());
}
+
+ //Right to left
+ $xmlWriter->writeAttributeIf($style->isBidi(), 'style:writing-mode', 'rl-tb');
+
$xmlWriter->endElement(); //style:paragraph-properties
$xmlWriter->endElement(); //style:style
diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php
index c64dee4f..646f2e44 100644
--- a/src/PhpWord/Writer/ODText/Style/Table.php
+++ b/src/PhpWord/Writer/ODText/Style/Table.php
@@ -43,6 +43,7 @@ class Table extends AbstractStyle
//$xmlWriter->writeAttribute('style:width', 'table');
$xmlWriter->writeAttribute('style:rel-width', 100);
$xmlWriter->writeAttribute('table:align', 'center');
+ $xmlWriter->writeAttributeIf($style->isBidiVisual(), 'style:writing-mode', 'rl-tb');
$xmlWriter->endElement(); // style:table-properties
$xmlWriter->endElement(); // style:style
diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php
index 7f49be7c..443d6705 100644
--- a/src/PhpWord/Writer/Word2007/Style/Table.php
+++ b/src/PhpWord/Writer/Word2007/Style/Table.php
@@ -86,6 +86,9 @@ class Table extends AbstractStyle
$styleWriter = new TablePosition($xmlWriter, $style->getPosition());
$styleWriter->write();
+ //Right to left
+ $xmlWriter->writeElementIf($style->isBidiVisual() !== null, 'w:bidiVisual', 'w:val', $this->writeOnOf($style->isBidiVisual()));
+
$this->writeMargin($xmlWriter, $style);
$this->writeBorder($xmlWriter, $style);
diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php
index 4a7add16..ad48dcba 100644
--- a/tests/PhpWord/Reader/Word2007/StyleTest.php
+++ b/tests/PhpWord/Reader/Word2007/StyleTest.php
@@ -147,6 +147,24 @@ class StyleTest extends AbstractTestReader
$this->assertSame(2160, $tableStyle->getIndent()->getValue());
}
+ public function testReadTableRTL()
+ {
+ $documentXml = '
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(array('document' => $documentXml));
+
+ $elements = $phpWord->getSection(0)->getElements();
+ $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]);
+ $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle());
+ /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */
+ $tableStyle = $elements[0]->getStyle();
+ $this->assertTrue($tableStyle->isBidiVisual());
+ }
+
public function testReadHidden()
{
$documentXml = '
diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php
index ec3b2483..8e5cb634 100644
--- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php
+++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php
@@ -141,4 +141,21 @@ class TableTest extends \PHPUnit\Framework\TestCase
$this->assertSame($value, (int) $doc->getElementAttribute($path, 'w:w'));
$this->assertSame($type, $doc->getElementAttribute($path, 'w:type'));
}
+
+ public function testRigthToLeft()
+ {
+ $tableStyle = new Table();
+ $tableStyle->setBidiVisual(true);
+
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $section = $phpWord->addSection();
+ $table = $section->addTable($tableStyle);
+ $table->addRow();
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $path = '/w:document/w:body/w:tbl/w:tblPr/w:bidiVisual';
+ $this->assertTrue($doc->elementExists($path));
+ $this->assertEquals('1', $doc->getElementAttribute($path, 'w:val'));
+ }
}
From 6aae8bdccb9aca8ba3b40aa0e5ab942fe7eddc10 Mon Sep 17 00:00:00 2001
From: troosan
Date: Thu, 3 Jan 2019 11:36:28 +0100
Subject: [PATCH 10/53] update doc and release note
---
CHANGELOG.md | 1 +
docs/styles.rst | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 735264f1..c7030a5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
v0.17.0 (?? ??? 2019)
----------------------
### Added
+- Add RightToLeft table presentation. @troosan #1550
### Fixed
diff --git a/docs/styles.rst b/docs/styles.rst
index 31d04a3b..2be6eb94 100644
--- a/docs/styles.rst
+++ b/docs/styles.rst
@@ -108,11 +108,12 @@ Available Table style options:
- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*.
- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*.
- ``indent``. Table indent from leading margin. Must be an instance of ``\PhpOffice\PhpWord\ComplexType\TblWidth``.
-- ``width``. Table width in percent.
+- ``width``. Table width in Fiftieths of a Percent or Twentieths of a Point.
- ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*.
- ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants.
- ``cellSpacing`` Cell spacing in *twip*
- ``position`` Floating Table Positioning, see below for options
+- ``bidiVisual`` Present table as Right-To-Left
Floating Table Positioning options:
From 3c9fa2df13517c3ffa29aaaea7da6c3455a909e6 Mon Sep 17 00:00:00 2001
From: Stathis Papadopoulos
Date: Mon, 28 Jan 2019 10:50:28 +0100
Subject: [PATCH 11/53] Language::validateLocale should pass with locale 'zxx'.
---
src/PhpWord/Style/Language.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php
index 8174f6ee..dd3ed819 100644
--- a/src/PhpWord/Style/Language.php
+++ b/src/PhpWord/Style/Language.php
@@ -229,7 +229,7 @@ final class Language extends AbstractStyle
return strtolower($locale) . '-' . strtoupper($locale);
}
- if ($locale !== null && strstr($locale, '-') === false) {
+ if ($locale !== null && $locale !== 'zxx' && strstr($locale, '-') === false) {
throw new \InvalidArgumentException($locale . ' is not a valid language code');
}
From 67f3bd369cb42cc547d832035d25e3912447071e Mon Sep 17 00:00:00 2001
From: troosan
Date: Thu, 31 Jan 2019 01:26:19 +0100
Subject: [PATCH 12/53] Add methods to replace macro with ComplexType
---
.gitignore | 1 -
samples/Sample_40_TemplateSetComplexValue.php | 45 ++++
.../Sample_40_TemplateSetComplexValue.docx | Bin 0 -> 14735 bytes
src/PhpWord/TemplateProcessor.php | 212 ++++++++++++++++++
tests/PhpWord/TemplateProcessorTest.php | 128 +++++++++++
.../_includes/TestableTemplateProcesor.php | 28 +++
6 files changed, 413 insertions(+), 1 deletion(-)
create mode 100644 samples/Sample_40_TemplateSetComplexValue.php
create mode 100644 samples/resources/Sample_40_TemplateSetComplexValue.docx
diff --git a/.gitignore b/.gitignore
index b2ec7e23..dd858cea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,7 +13,6 @@ composer.phar
vendor
/report
/build
-/samples/resources
/samples/results
/.settings
phpword.ini
diff --git a/samples/Sample_40_TemplateSetComplexValue.php b/samples/Sample_40_TemplateSetComplexValue.php
new file mode 100644
index 00000000..094823f7
--- /dev/null
+++ b/samples/Sample_40_TemplateSetComplexValue.php
@@ -0,0 +1,45 @@
+addText('This title has been set ', array('bold' => true, 'italic' => true, 'color' => 'blue'));
+$title->addText('dynamically', array('bold' => true, 'italic' => true, 'color' => 'red', 'underline' => 'single'));
+$templateProcessor->setComplexBlock('title', $title);
+
+$inline = new TextRun();
+$inline->addText('by a red italic text', array('italic' => true, 'color' => 'red'));
+$templateProcessor->setComplexValue('inline', $inline);
+
+$table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP));
+$table->addRow();
+$table->addCell(150)->addText('Cell A1');
+$table->addCell(150)->addText('Cell A2');
+$table->addCell(150)->addText('Cell A3');
+$table->addRow();
+$table->addCell(150)->addText('Cell B1');
+$table->addCell(150)->addText('Cell B2');
+$table->addCell(150)->addText('Cell B3');
+$templateProcessor->setComplexBlock('table', $table);
+
+$field = new Field('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat'));
+$templateProcessor->setComplexValue('field', $field);
+
+// $link = new Link('https://github.com/PHPOffice/PHPWord');
+// $templateProcessor->setComplexValue('link', $link);
+
+echo date('H:i:s'), ' Saving the result document...', EOL;
+$templateProcessor->saveAs('results/Sample_40_TemplateSetComplexValue.docx');
+
+echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_40_TemplateSetComplexValue.docx');
+if (!CLI) {
+ include_once 'Sample_Footer.php';
+}
diff --git a/samples/resources/Sample_40_TemplateSetComplexValue.docx b/samples/resources/Sample_40_TemplateSetComplexValue.docx
new file mode 100644
index 0000000000000000000000000000000000000000..7265908e8c5c54842b11079507f3fea33af4b8e1
GIT binary patch
literal 14735
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
DlaFJ(
literal 0
HcmV?d00001
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index fbfdd9dc..498cf701 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -18,6 +18,7 @@
namespace PhpOffice\PhpWord;
use PhpOffice\Common\Text;
+use PhpOffice\Common\XMLWriter;
use PhpOffice\PhpWord\Escaper\RegExp;
use PhpOffice\PhpWord\Escaper\Xml;
use PhpOffice\PhpWord\Exception\CopyFileException;
@@ -249,6 +250,46 @@ class TemplateProcessor
return $subject;
}
+ /**
+ * @param string $search
+ * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType
+ */
+ public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElement $complexType)
+ {
+ $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1);
+ $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName;
+
+ $xmlWriter = new XMLWriter();
+ /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */
+ $elementWriter = new $objectClass($xmlWriter, $complexType, true);
+ $elementWriter->write();
+
+ $where = $this->findContainingXmlBlockForMacro($search, 'w:r');
+ $block = $this->getSlice($where['start'], $where['end']);
+ $textParts = $this->splitTextIntoTexts($block);
+ $this->replaceXmlBlock($search, $textParts, 'w:r');
+
+ $search = static::ensureMacroCompleted($search);
+ $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:r');
+ }
+
+ /**
+ * @param string $search
+ * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType
+ */
+ public function setComplexBlock($search, \PhpOffice\PhpWord\Element\AbstractElement $complexType)
+ {
+ $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1);
+ $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName;
+
+ $xmlWriter = new XMLWriter();
+ /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */
+ $elementWriter = new $objectClass($xmlWriter, $complexType, false);
+ $elementWriter->write();
+
+ $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:p');
+ }
+
/**
* @param mixed $search
* @param mixed $replace
@@ -685,6 +726,7 @@ class TemplateProcessor
public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null)
{
$xmlBlock = null;
+ $matches = array();
preg_match(
'/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is',
$this->tempDocumentMainPart,
@@ -724,6 +766,7 @@ class TemplateProcessor
*/
public function replaceBlock($blockname, $replacement)
{
+ $matches = array();
preg_match(
'/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is',
$this->tempDocumentMainPart,
@@ -865,6 +908,7 @@ class TemplateProcessor
*/
protected function getVariablesForPart($documentPartXML)
{
+ $matches = array();
preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches);
return $matches[1];
@@ -893,6 +937,7 @@ class TemplateProcessor
$pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~';
+ $matches = array();
preg_match($pattern, $contentTypes, $matches);
return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml';
@@ -1031,4 +1076,171 @@ class TemplateProcessor
return $results;
}
+
+ /**
+ * Replace an XML block surrounding a macro with a new block
+ *
+ * @param string $macro Name of macro
+ * @param string $block New block content
+ * @param string $blockType XML tag type of block
+ * @return \PhpOffice\PhpWord\TemplateProcessor Fluent interface
+ */
+ protected function replaceXmlBlock($macro, $block, $blockType = 'w:p')
+ {
+ $where = $this->findContainingXmlBlockForMacro($macro, $blockType);
+ if (false !== $where) {
+ $this->tempDocumentMainPart = $this->getSlice(0, $where['start']) . $block . $this->getSlice($where['end']);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Find start and end of XML block containing the given macro
+ * e.g. ...${macro}...
+ *
+ * Note that only the first instance of the macro will be found
+ *
+ * @param string $macro Name of macro
+ * @param string $blockType XML tag for block
+ * @return bool|int[] FALSE if not found, otherwise array with start and end
+ */
+ protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p')
+ {
+ $macroPos = $this->findMacro($macro);
+ if (false === $macroPos) {
+ return false;
+ }
+ $start = $this->findXmlBlockStart($macroPos, $blockType);
+ if (0 > $start) {
+ return false;
+ }
+ $end = $this->findXmlBlockEnd($start, $blockType);
+ if (0 > $end) {
+ return false;
+ }
+
+ return array('start' => $start, 'end' => $end);
+ }
+
+ /**
+ * Find start and end of XML block containing the given block macro
+ * e.g. ...${macro}...${/macro}...
+ *
+ * Note that only the first instance of the macro will be found
+ *
+ * @param string $macro Name of macro
+ * @param string $blockType XML tag for block
+ * @return bool|int[] FALSE if not found, otherwise array with start and end
+ */
+ protected function findContainingXmlBlockForBlockMacro($macro, $blockType = 'w:p')
+ {
+ $macroStartPos = $this->findMacro($macro);
+ if (0 > $macroStartPos) {
+ return false;
+ }
+ $macroEndPos = $this->findMacro('/' . $macro, $macroStartPos);
+ if (0 > $macroEndPos) {
+ return false;
+ }
+ $start = $this->findXmlBlockStart($macroStartPos, $blockType);
+ if (0 > $start) {
+ return false;
+ }
+ $end = $this->findXmlBlockEnd($macroEndPos, $blockType);
+ if (0 > $end) {
+ return false;
+ }
+
+ return array('start' => $start, 'end' => $end);
+ }
+
+ /**
+ * Find the position of (the start of) a macro
+ *
+ * Returns -1 if not found, otherwise position of opening $
+ *
+ * Note that only the first instance of the macro will be found
+ *
+ * @param string $search Macro name
+ * @param string $offset Offset from which to start searching
+ * @return int -1 if macro not found
+ */
+ protected function findMacro($search, $offset = 0)
+ {
+ $search = static::ensureMacroCompleted($search);
+ $pos = strpos($this->tempDocumentMainPart, $search, $offset);
+
+ return ($pos === false) ? -1 : $pos;
+ }
+
+ /**
+ * Find the start position of the nearest XML block start before $offset
+ *
+ * @param int $offset Search position
+ * @param string $blockType XML Block tag
+ * @return int -1 if block start not found
+ */
+ protected function findXmlBlockStart($offset, $blockType)
+ {
+ // first try XML tag with attributes
+ $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', ((strlen($this->tempDocumentMainPart) - $offset) * -1));
+ // if not found, or if found but contains the XML tag without attribute
+ if (false === $blockStart || strrpos($this->getSlice($blockStart, $offset), '<' . $blockType . '>')) {
+ // also try XML tag without attributes
+ $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', ((strlen($this->tempDocumentMainPart) - $offset) * -1));
+ }
+
+ return ($blockStart === false) ? -1 : $blockStart;
+ }
+
+ /**
+ * Find the nearest block end position after $offset
+ *
+ * @param int $offset Search position
+ * @param string $blockType XML Block tag
+ * @return int -1 if block end not found
+ */
+ protected function findXmlBlockEnd($offset, $blockType)
+ {
+ $blockEndStart = strpos($this->tempDocumentMainPart, '' . $blockType . '>', $offset);
+ // return position of end of tag if found, otherwise -1
+
+ return ($blockEndStart === false) ? -1 : $blockEndStart + 3 + strlen($blockType);
+ }
+
+ /**
+ * Splits a w:r/w:t into a list of w:r where each ${macro} is in a separate w:r
+ *
+ * @param string $text
+ * @return string
+ */
+ protected function splitTextIntoTexts($text)
+ {
+ if (!$this->textNeedsSplitting($text)) {
+ return $text;
+ }
+ $matches = array();
+ if (preg_match('/()/i', $text, $matches)) {
+ $extractedStyle = $matches[0];
+ } else {
+ $extractedStyle = '';
+ }
+
+ $unformattedText = preg_replace('/>\s+', '><', $text);
+ $result = str_replace(array('${', '}'), array('' . $extractedStyle . '${', '}' . $extractedStyle . ''), $unformattedText);
+
+ return str_replace(array('' . $extractedStyle . '', '', ''), array('', '', ''), $result);
+ }
+
+ /**
+ * Returns true if string contains a macro that is not in it's own w:r
+ *
+ * @param string $text
+ * @return bool
+ */
+ protected function textNeedsSplitting($text)
+ {
+ return preg_match('/[^>]\${|}[^<]/i', $text) == 1;
+ }
}
diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php
index 286ffe97..4c9f2358 100644
--- a/tests/PhpWord/TemplateProcessorTest.php
+++ b/tests/PhpWord/TemplateProcessorTest.php
@@ -17,6 +17,9 @@
namespace PhpOffice\PhpWord;
+use PhpOffice\PhpWord\Element\Text;
+use PhpOffice\PhpWord\Element\TextRun;
+
/**
* @covers \PhpOffice\PhpWord\TemplateProcessor
* @coversDefaultClass \PhpOffice\PhpWord\TemplateProcessor
@@ -307,6 +310,59 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
);
}
+ public function testSetComplexValue()
+ {
+ $title = new TextRun();
+ $title->addText('This is my title');
+
+ $firstname = new Text('Donald');
+ $lastname = new Text('Duck');
+
+ $mainPart = '
+
+
+ Hello ${document-title}
+
+
+
+
+ Hello ${firstname} ${lastname}
+
+ ';
+
+ $result = '
+
+
+
+
+ This is my title
+
+
+
+
+ Hello
+
+
+
+ Donald
+
+
+
+
+
+
+ Duck
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setComplexBlock('document-title', $title);
+ $templateProcessor->setComplexValue('firstname', $firstname);
+ $templateProcessor->setComplexValue('lastname', $lastname);
+
+ $this->assertEquals(preg_replace('/>\s+', '><', $result), preg_replace('/>\s+', '><', $templateProcessor->getMainPart()));
+ }
+
/**
* @covers ::setValues
* @test
@@ -675,4 +731,76 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
$variables = $templateProcessor->getVariablesForPart('$15,000.00. ${variable_name}');
$this->assertEquals(array('variable_name'), $variables);
}
+
+ /**
+ * @covers ::textNeedsSplitting
+ */
+ public function testTextNeedsSplitting()
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+
+ $this->assertFalse($templateProcessor->textNeedsSplitting('${nothing-to-replace}'));
+
+ $text = 'Hello ${firstname} ${lastname}';
+ $this->assertTrue($templateProcessor->textNeedsSplitting($text));
+ $splitText = $templateProcessor->splitTextIntoTexts($text);
+ $this->assertFalse($templateProcessor->textNeedsSplitting($splitText));
+ }
+
+ /**
+ * @covers ::splitTextIntoTexts
+ */
+ public function testSplitTextIntoTexts()
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+
+ $splitText = $templateProcessor->splitTextIntoTexts('${nothing-to-replace}');
+ $this->assertEquals('${nothing-to-replace}', $splitText);
+
+ $splitText = $templateProcessor->splitTextIntoTexts('Hello ${firstname} ${lastname}');
+ $this->assertEquals('Hello ${firstname} ${lastname}', $splitText);
+ }
+
+ public function testFindXmlBlockStart()
+ {
+ $toFind = '
+
+
+
+
+ This whole paragraph will be replaced with my ${title}
+ ';
+ $mainPart = '
+
+
+
+
+
+
+ ${value1} ${value2}
+
+
+
+
+
+
+ .
+
+
+
+
+
+
+
+
+
+ ' . $toFind . '
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $position = $templateProcessor->findContainingXmlBlockForMacro('${title}', 'w:r');
+
+ $this->assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end']));
+ }
}
diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php
index 3b6f5b56..44c0bb55 100644
--- a/tests/PhpWord/_includes/TestableTemplateProcesor.php
+++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php
@@ -35,6 +35,16 @@ class TestableTemplateProcesor extends TemplateProcessor
return parent::fixBrokenMacros($documentPart);
}
+ public function splitTextIntoTexts($text)
+ {
+ return parent::splitTextIntoTexts($text);
+ }
+
+ public function textNeedsSplitting($text)
+ {
+ return parent::textNeedsSplitting($text);
+ }
+
public function getVariablesForPart($documentPartXML)
{
$documentPartXML = parent::fixBrokenMacros($documentPartXML);
@@ -42,6 +52,24 @@ class TestableTemplateProcesor extends TemplateProcessor
return parent::getVariablesForPart($documentPartXML);
}
+ public function findXmlBlockStart($offset, $blockType)
+ {
+ return parent::findXmlBlockStart($offset, $blockType);
+ }
+
+ public function findContainingXmlBlockForMacro($macro, $blockType = 'w:p')
+ {
+ return parent::findContainingXmlBlockForMacro($macro, $blockType);
+ }
+
+ public function getSlice($startPosition, $endPosition = 0)
+ {
+ return parent::getSlice($startPosition, $endPosition);
+ }
+
+ /**
+ * @return string
+ */
public function getMainPart()
{
return $this->tempDocumentMainPart;
From d862b1f267ca86635593b3af3c637889248602ed Mon Sep 17 00:00:00 2001
From: troosan
Date: Thu, 31 Jan 2019 01:32:00 +0100
Subject: [PATCH 13/53] update documentation
---
docs/templates-processing.rst | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst
index 325de8de..5b32aa18 100644
--- a/docs/templates-processing.rst
+++ b/docs/templates-processing.rst
@@ -215,3 +215,32 @@ Applies the XSL stylesheet passed to header part, footer part and main part
$xslDomDocument = new \DOMDocument();
$xslDomDocument->load('/path/to/my/stylesheet.xsl');
$templateProcessor->applyXslStyleSheet($xslDomDocument);
+
+setComplexValue
+"""""""""""""""
+Raplaces a ${macro} with the ComplexType passed.
+See ``Sample_40_TemplateSetComplexValue.php`` for examples.
+
+.. code-block:: php
+
+ $inline = new TextRun();
+ $inline->addText('by a red italic text', array('italic' => true, 'color' => 'red'));
+ $templateProcessor->setComplexValue('inline', $inline);
+
+setComplexBlock
+"""""""""""""""
+Raplaces a ${macro} with the ComplexType passed.
+See ``Sample_40_TemplateSetComplexValue.php`` for examples.
+
+.. code-block:: php
+
+ $table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP));
+ $table->addRow();
+ $table->addCell(150)->addText('Cell A1');
+ $table->addCell(150)->addText('Cell A2');
+ $table->addCell(150)->addText('Cell A3');
+ $table->addRow();
+ $table->addCell(150)->addText('Cell B1');
+ $table->addCell(150)->addText('Cell B2');
+ $table->addCell(150)->addText('Cell B3');
+ $templateProcessor->setComplexBlock('table', $table);
From bc448aed6c7df7782d9655d5df99e2789090daa6 Mon Sep 17 00:00:00 2001
From: troosan
Date: Mon, 4 Feb 2019 21:53:19 +0100
Subject: [PATCH 14/53] improve code coverage
---
src/PhpWord/TemplateProcessor.php | 42 ++++---------------------
tests/PhpWord/TemplateProcessorTest.php | 27 ++++++++++++++++
2 files changed, 33 insertions(+), 36 deletions(-)
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index 498cf701..9e12028d 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -1108,7 +1108,7 @@ class TemplateProcessor
protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p')
{
$macroPos = $this->findMacro($macro);
- if (false === $macroPos) {
+ if (0 > $macroPos) {
return false;
}
$start = $this->findXmlBlockStart($macroPos, $blockType);
@@ -1116,39 +1116,8 @@ class TemplateProcessor
return false;
}
$end = $this->findXmlBlockEnd($start, $blockType);
- if (0 > $end) {
- return false;
- }
-
- return array('start' => $start, 'end' => $end);
- }
-
- /**
- * Find start and end of XML block containing the given block macro
- * e.g. ...${macro}...${/macro}...
- *
- * Note that only the first instance of the macro will be found
- *
- * @param string $macro Name of macro
- * @param string $blockType XML tag for block
- * @return bool|int[] FALSE if not found, otherwise array with start and end
- */
- protected function findContainingXmlBlockForBlockMacro($macro, $blockType = 'w:p')
- {
- $macroStartPos = $this->findMacro($macro);
- if (0 > $macroStartPos) {
- return false;
- }
- $macroEndPos = $this->findMacro('/' . $macro, $macroStartPos);
- if (0 > $macroEndPos) {
- return false;
- }
- $start = $this->findXmlBlockStart($macroStartPos, $blockType);
- if (0 > $start) {
- return false;
- }
- $end = $this->findXmlBlockEnd($macroEndPos, $blockType);
- if (0 > $end) {
+ //if not found or if resulting string does not contain the macro we are searching for
+ if (0 > $end || strstr($this->getSlice($start, $end), $macro) === false) {
return false;
}
@@ -1183,12 +1152,13 @@ class TemplateProcessor
*/
protected function findXmlBlockStart($offset, $blockType)
{
+ $reverseOffset = (strlen($this->tempDocumentMainPart) - $offset) * -1;
// first try XML tag with attributes
- $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', ((strlen($this->tempDocumentMainPart) - $offset) * -1));
+ $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', $reverseOffset);
// if not found, or if found but contains the XML tag without attribute
if (false === $blockStart || strrpos($this->getSlice($blockStart, $offset), '<' . $blockType . '>')) {
// also try XML tag without attributes
- $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', ((strlen($this->tempDocumentMainPart) - $offset) * -1));
+ $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', $reverseOffset);
}
return ($blockStart === false) ? -1 : $blockStart;
diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php
index 4c9f2358..043ad1ff 100644
--- a/tests/PhpWord/TemplateProcessorTest.php
+++ b/tests/PhpWord/TemplateProcessorTest.php
@@ -803,4 +803,31 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
$this->assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end']));
}
+
+ public function testShouldReturnFalseIfXmlBlockNotFound()
+ {
+ $mainPart = '
+
+
+
+
+
+ this is my text containing a ${macro}
+
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+
+ //non-existing macro
+ $result = $templateProcessor->findContainingXmlBlockForMacro('${fake-macro}', 'w:p');
+ $this->assertFalse($result);
+
+ //existing macro but not inside node looked for
+ $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:fake-node');
+ $this->assertFalse($result);
+
+ //existing macro but end tag not found after macro
+ $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:rPr');
+ $this->assertFalse($result);
+ }
}
From d2b0b317e025d6e42bd8389258b3e6ca9d4dfed1 Mon Sep 17 00:00:00 2001
From: troosan
Date: Mon, 4 Feb 2019 22:57:33 +0100
Subject: [PATCH 15/53] fix scrutinizer warnings
---
src/PhpWord/TemplateProcessor.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index 9e12028d..0a366617 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -1088,7 +1088,7 @@ class TemplateProcessor
protected function replaceXmlBlock($macro, $block, $blockType = 'w:p')
{
$where = $this->findContainingXmlBlockForMacro($macro, $blockType);
- if (false !== $where) {
+ if (is_array($where)) {
$this->tempDocumentMainPart = $this->getSlice(0, $where['start']) . $block . $this->getSlice($where['end']);
}
@@ -1132,7 +1132,7 @@ class TemplateProcessor
* Note that only the first instance of the macro will be found
*
* @param string $search Macro name
- * @param string $offset Offset from which to start searching
+ * @param int $offset Offset from which to start searching
* @return int -1 if macro not found
*/
protected function findMacro($search, $offset = 0)
From 58a2849e38b566ea3bf267d0f8b5bb2729be0d6b Mon Sep 17 00:00:00 2001
From: troosan
Date: Mon, 4 Feb 2019 23:59:37 +0100
Subject: [PATCH 16/53] Add reading of the settings part
---
src/PhpWord/TemplateProcessor.php | 35 +++++++++++++++++++
tests/PhpWord/TemplateProcessorTest.php | 14 ++++++++
.../_includes/TestableTemplateProcesor.php | 11 +++++-
3 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index 0a366617..0f685bc4 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -49,6 +49,13 @@ class TemplateProcessor
*/
protected $tempDocumentMainPart;
+ /**
+ * Content of settings part (in XML format) of the temporary document
+ *
+ * @var string
+ */
+ protected $tempDocumentSettingsPart;
+
/**
* Content of headers (in XML format) of the temporary document
*
@@ -120,6 +127,7 @@ class TemplateProcessor
}
$this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName());
+ $this->tempDocumentSettingsPart = $this->readPartWithRels($this->getSettingsPartName());
$this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName());
}
@@ -792,6 +800,22 @@ class TemplateProcessor
$this->replaceBlock($blockname, '');
}
+ /**
+ * Automatically Recalculate Fields on Open
+ *
+ * @param bool $update
+ */
+ public function setUpdateFields($update = true)
+ {
+ $string = $update ? 'true' : 'false';
+ $matches = array();
+ if (preg_match('//', $this->tempDocumentSettingsPart, $matches)) {
+ $this->tempDocumentSettingsPart = str_replace($matches[0], '', $this->tempDocumentSettingsPart);
+ } else {
+ $this->tempDocumentSettingsPart = str_replace('', '', $this->tempDocumentSettingsPart);
+ }
+ }
+
/**
* Saves the result document.
*
@@ -806,6 +830,7 @@ class TemplateProcessor
}
$this->savePartWithRels($this->getMainPartName(), $this->tempDocumentMainPart);
+ $this->savePartWithRels($this->getSettingsPartName(), $this->tempDocumentSettingsPart);
foreach ($this->tempDocumentFooters as $index => $xml) {
$this->savePartWithRels($this->getFooterName($index), $xml);
@@ -943,6 +968,16 @@ class TemplateProcessor
return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml';
}
+ /**
+ * The name of the file containing the Settings part
+ *
+ * @return string
+ */
+ protected function getSettingsPartName()
+ {
+ return 'word/settings.xml';
+ }
+
/**
* Get the name of the footer file for $index.
*
diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php
index 043ad1ff..4caca77a 100644
--- a/tests/PhpWord/TemplateProcessorTest.php
+++ b/tests/PhpWord/TemplateProcessorTest.php
@@ -830,4 +830,18 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
$result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:rPr');
$this->assertFalse($result);
}
+
+ public function testShouldMakeFieldsUpdateOnOpen()
+ {
+ $settingsPart = '
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor(null, $settingsPart);
+
+ $templateProcessor->setUpdateFields(true);
+ $this->assertContains('', $templateProcessor->getSettingsPart());
+
+ $templateProcessor->setUpdateFields(false);
+ $this->assertContains('', $templateProcessor->getSettingsPart());
+ }
}
diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php
index 44c0bb55..80cc748f 100644
--- a/tests/PhpWord/_includes/TestableTemplateProcesor.php
+++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php
@@ -25,9 +25,10 @@ namespace PhpOffice\PhpWord;
*/
class TestableTemplateProcesor extends TemplateProcessor
{
- public function __construct($mainPart = null)
+ public function __construct($mainPart = null, $settingsPart = null)
{
$this->tempDocumentMainPart = $mainPart;
+ $this->tempDocumentSettingsPart = $settingsPart;
}
public function fixBrokenMacros($documentPart)
@@ -74,4 +75,12 @@ class TestableTemplateProcesor extends TemplateProcessor
{
return $this->tempDocumentMainPart;
}
+
+ /**
+ * @return string
+ */
+ public function getSettingsPart()
+ {
+ return $this->tempDocumentSettingsPart;
+ }
}
From 235cc1205c199a0cace54f858982ddbae7acdacd Mon Sep 17 00:00:00 2001
From: troosan
Date: Tue, 5 Feb 2019 21:42:14 +0100
Subject: [PATCH 17/53] implement support for section vAlign
---
CHANGELOG.md | 1 +
docs/styles.rst | 2 ++
samples/Sample_03_Sections.php | 8 +++++
src/PhpWord/Reader/Word2007/Document.php | 1 +
src/PhpWord/SimpleType/VerticalJc.php | 36 +++++++++++++++++++
src/PhpWord/Style/Cell.php | 15 ++++++--
src/PhpWord/Style/Section.php | 34 ++++++++++++++++++
src/PhpWord/Writer/Word2007/Style/Section.php | 4 +++
tests/PhpWord/Reader/Word2007/StyleTest.php | 13 +++++++
tests/PhpWord/Style/CellTest.php | 4 ++-
tests/PhpWord/Style/SectionTest.php | 16 +++++++++
11 files changed, 131 insertions(+), 3 deletions(-)
create mode 100644 src/PhpWord/SimpleType/VerticalJc.php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7030a5b..e5ce3c15 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ v0.17.0 (?? ??? 2019)
----------------------
### Added
- Add RightToLeft table presentation. @troosan #1550
+- Add support for page vertical alignment. @troosan #672 #1569
### Fixed
diff --git a/docs/styles.rst b/docs/styles.rst
index 2be6eb94..27f8ee66 100644
--- a/docs/styles.rst
+++ b/docs/styles.rst
@@ -32,6 +32,8 @@ Available Section style options:
See ``\PhpOffice\PhpWord\Style\Section::ORIENTATION_...`` class constants for possible values
- ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged.
- ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged.
+- ``vAlign``. Vertical Page Alignment
+ See ``\PhpOffice\PhpWord\SimpleType\VerticalJc`` for possible values
.. _font-style:
diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php
index a7b5b13d..5bb9ecc2 100644
--- a/samples/Sample_03_Sections.php
+++ b/samples/Sample_03_Sections.php
@@ -1,4 +1,6 @@
addSection(
);
$section->addText('This section uses other margins with folio papersize.');
+// The text of this section is vertically centered
+$section = $phpWord->addSection(
+ array('vAlign' => VerticalJc::CENTER)
+);
+$section->addText('This section is vertically centered.');
+
// New portrait section with Header & Footer
$section = $phpWord->addSection(
array(
diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php
index 4e37541b..f0d1194a 100644
--- a/src/PhpWord/Reader/Word2007/Document.php
+++ b/src/PhpWord/Reader/Word2007/Document.php
@@ -106,6 +106,7 @@ class Document extends AbstractPart
{
$styleDefs = array(
'breakType' => array(self::READ_VALUE, 'w:type'),
+ 'vAlign' => array(self::READ_VALUE, 'w:vAlign'),
'pageSizeW' => array(self::READ_VALUE, 'w:pgSz', 'w:w'),
'pageSizeH' => array(self::READ_VALUE, 'w:pgSz', 'w:h'),
'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'),
diff --git a/src/PhpWord/SimpleType/VerticalJc.php b/src/PhpWord/SimpleType/VerticalJc.php
new file mode 100644
index 00000000..2a37de41
--- /dev/null
+++ b/src/PhpWord/SimpleType/VerticalJc.php
@@ -0,0 +1,36 @@
+vAlign = $this->setEnumVal($value, $enum, $this->vAlign);
+ VerticalJc::validate($value);
+ $this->vAlign = $this->setEnumVal($value, VerticalJc::values(), $this->vAlign);
return $this;
}
diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php
index 162e08e0..3989a31e 100644
--- a/src/PhpWord/Style/Section.php
+++ b/src/PhpWord/Style/Section.php
@@ -17,6 +17,8 @@
namespace PhpOffice\PhpWord\Style;
+use PhpOffice\PhpWord\SimpleType\VerticalJc;
+
/**
* Section settings
*/
@@ -166,6 +168,14 @@ class Section extends Border
*/
private $lineNumbering;
+ /**
+ * Vertical Text Alignment on Page
+ * One of \PhpOffice\PhpWord\SimpleType\VerticalJc
+ *
+ * @var string
+ */
+ private $vAlign;
+
/**
* Create new instance
*/
@@ -599,4 +609,28 @@ class Section extends Border
return $this;
}
+
+ /**
+ * Get vertical alignment
+ *
+ * @return \PhpOffice\PhpWord\SimpleType\VerticalJc
+ */
+ public function getVAlign()
+ {
+ return $this->vAlign;
+ }
+
+ /**
+ * Set vertical alignment
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setVAlign($value = null)
+ {
+ VerticalJc::validate($value);
+ $this->vAlign = $value;
+
+ return $this;
+ }
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php
index af77396d..1122b6ff 100644
--- a/src/PhpWord/Writer/Word2007/Style/Section.php
+++ b/src/PhpWord/Writer/Word2007/Style/Section.php
@@ -48,6 +48,10 @@ class Section extends AbstractStyle
$xmlWriter->writeAttribute('w:h', $style->getPageSizeH());
$xmlWriter->endElement(); // w:pgSz
+ // Vertical alignment
+ $vAlign = $style->getVAlign();
+ $xmlWriter->writeElementIf(!is_null($vAlign), 'w:vAlign', 'w:val', $vAlign);
+
// Margins
$margins = array(
'w:top' => array('getMarginTop', SectionStyle::DEFAULT_MARGIN),
diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php
index ad48dcba..91e96c4a 100644
--- a/tests/PhpWord/Reader/Word2007/StyleTest.php
+++ b/tests/PhpWord/Reader/Word2007/StyleTest.php
@@ -22,6 +22,7 @@ use PhpOffice\PhpWord\SimpleType\TblWidth;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Table;
use PhpOffice\PhpWord\Style\TablePosition;
+use PhpOffice\PhpWord\SimpleType\VerticalJc;
/**
* Test class for PhpOffice\PhpWord\Reader\Word2007\Styles
@@ -213,4 +214,16 @@ class StyleTest extends AbstractTestReader
$this->getDocumentFromString(array('styles' => $documentXml));
$this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', Style::getStyle($name));
}
+
+ public function testPageVerticalAlign()
+ {
+ $documentXml = '
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(array('document' => $documentXml));
+
+ $sectionStyle = $phpWord->getSection(0)->getStyle();
+ $this->assertEquals(VerticalJc::CENTER, $sectionStyle->getVAlign());
+ }
}
diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php
index db789fdc..3c31a457 100644
--- a/tests/PhpWord/Style/CellTest.php
+++ b/tests/PhpWord/Style/CellTest.php
@@ -17,6 +17,8 @@
namespace PhpOffice\PhpWord\Style;
+use PhpOffice\PhpWord\SimpleType\VerticalJc;
+
/**
* Test class for PhpOffice\PhpWord\Style\Cell
*
@@ -33,7 +35,7 @@ class CellTest extends \PHPUnit\Framework\TestCase
$object = new Cell();
$attributes = array(
- 'valign' => Cell::VALIGN_TOP,
+ 'valign' => VerticalJc::TOP,
'textDirection' => Cell::TEXT_DIR_BTLR,
'bgColor' => 'FFFF00',
'borderTopSize' => 120,
diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php
index b26d1d94..59d18167 100644
--- a/tests/PhpWord/Style/SectionTest.php
+++ b/tests/PhpWord/Style/SectionTest.php
@@ -17,6 +17,8 @@
namespace PhpOffice\PhpWord\Style;
+use PhpOffice\PhpWord\SimpleType\VerticalJc;
+
/**
* Test class for PhpOffice\PhpWord\Style\Section
*
@@ -328,4 +330,18 @@ class SectionTest extends \PHPUnit\Framework\TestCase
$oSettings->setBreakType();
$this->assertNull($oSettings->getBreakType());
}
+
+ /**
+ * Vertical page alignment
+ */
+ public function testVerticalAlign()
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ $this->assertNull($oSettings->getVAlign());
+
+ $oSettings->setVAlign(VerticalJc::BOTH);
+ $this->assertEquals('both', $oSettings->getVAlign());
+ }
}
From e3020c0db3cafc74371d088ee26e91bae5ce3c45 Mon Sep 17 00:00:00 2001
From: troosan
Date: Tue, 5 Feb 2019 23:05:18 +0100
Subject: [PATCH 18/53] fix warnings
---
src/PhpWord/Style/Section.php | 2 +-
tests/PhpWord/Reader/Word2007/StyleTest.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php
index 3989a31e..ff9b0be0 100644
--- a/src/PhpWord/Style/Section.php
+++ b/src/PhpWord/Style/Section.php
@@ -613,7 +613,7 @@ class Section extends Border
/**
* Get vertical alignment
*
- * @return \PhpOffice\PhpWord\SimpleType\VerticalJc
+ * @return string
*/
public function getVAlign()
{
diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php
index 91e96c4a..a7308f1a 100644
--- a/tests/PhpWord/Reader/Word2007/StyleTest.php
+++ b/tests/PhpWord/Reader/Word2007/StyleTest.php
@@ -19,10 +19,10 @@ namespace PhpOffice\PhpWord\Reader\Word2007;
use PhpOffice\PhpWord\AbstractTestReader;
use PhpOffice\PhpWord\SimpleType\TblWidth;
+use PhpOffice\PhpWord\SimpleType\VerticalJc;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Table;
use PhpOffice\PhpWord\Style\TablePosition;
-use PhpOffice\PhpWord\SimpleType\VerticalJc;
/**
* Test class for PhpOffice\PhpWord\Reader\Word2007\Styles
From 5206c7f6905e965b76ceb18d72b51e525223a51e Mon Sep 17 00:00:00 2001
From: troosan
Date: Wed, 6 Feb 2019 18:19:01 +0100
Subject: [PATCH 19/53] fix parsing of border-color and add test
---
CHANGELOG.md | 2 ++
samples/Sample_26_Html.php | 2 +-
src/PhpWord/Shared/Html.php | 16 +++++++++++++++-
tests/PhpWord/Shared/HtmlTest.php | 7 ++++++-
4 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5ce3c15..9ec1deef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,9 +7,11 @@ v0.17.0 (?? ??? 2019)
----------------------
### Added
- Add RightToLeft table presentation. @troosan #1550
+- Set complex type in template @troosan #1565
- Add support for page vertical alignment. @troosan #672 #1569
### Fixed
+- Fix HTML border-color parsing. @troosan #1551 #1570
### Miscelaneous
- Use embedded http server to test loading of remote images @troosan #
diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php
index 82a5cf6e..6bd926fe 100644
--- a/samples/Sample_26_Html.php
+++ b/samples/Sample_26_Html.php
@@ -74,7 +74,7 @@ $html .= '
- | 1 | 2 |
+ | 1 | 2 |
| This is bold text | | 6 |
';
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 7f4bf825..66ddc9f5 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -581,7 +581,7 @@ class Html
$styles['spaceAfter'] = Converter::cssToPoint($cValue);
break;
case 'border-color':
- $styles['color'] = trim($cValue, '#');
+ self::mapBorderColor($styles, $cValue);
break;
case 'border-width':
$styles['borderSize'] = Converter::cssToPoint($cValue);
@@ -738,6 +738,20 @@ class Html
}
}
+ private static function mapBorderColor(&$styles, $cssBorderColor)
+ {
+ $numColors = substr_count($cssBorderColor, '#');
+ if ($numColors === 1) {
+ $styles['borderColor'] = trim($cssBorderColor, '#');
+ } elseif ($numColors > 1) {
+ $colors = explode(' ', $cssBorderColor);
+ $borders = array('borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor');
+ for ($i = 0; $i < min(4, $numColors, count($colors)); $i++) {
+ $styles[$borders[$i]] = $colors[$i];
+ }
+ }
+ }
+
/**
* Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc
*
diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php
index 2f9a4be4..43472324 100644
--- a/tests/PhpWord/Shared/HtmlTest.php
+++ b/tests/PhpWord/Shared/HtmlTest.php
@@ -298,7 +298,7 @@ class HtmlTest extends AbstractWebServerEmbeddedTest
| header a |
header b |
- header c |
+ header c |
@@ -313,6 +313,11 @@ class HtmlTest extends AbstractWebServerEmbeddedTest
$this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc'));
$this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc'));
$this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val'));
+ //check border colors
+ $this->assertEquals('#00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color'));
+ $this->assertEquals('#00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color'));
+ $this->assertEquals('#00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));
+ $this->assertEquals('#00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color'));
}
/**
From 3219950d5988fbc50c628a3930fff4bca294ad06 Mon Sep 17 00:00:00 2001
From: troosan
Date: Wed, 6 Feb 2019 22:07:42 +0100
Subject: [PATCH 20/53] trim color codes and add tests
---
src/PhpWord/Shared/Html.php | 4 +--
tests/PhpWord/Shared/HtmlTest.php | 47 +++++++++++++++++++++++++++----
2 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 66ddc9f5..89881822 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -516,7 +516,7 @@ class Html
$styles['alignment'] = self::mapAlign($cValue);
break;
case 'display':
- $styles['hidden'] = $cValue === 'none';
+ $styles['hidden'] = $cValue === 'none' || $cValue === 'hidden';
break;
case 'direction':
$styles['rtl'] = $cValue === 'rtl';
@@ -747,7 +747,7 @@ class Html
$colors = explode(' ', $cssBorderColor);
$borders = array('borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor');
for ($i = 0; $i < min(4, $numColors, count($colors)); $i++) {
- $styles[$borders[$i]] = $colors[$i];
+ $styles[$borders[$i]] = trim($colors[$i], '#');
}
}
}
diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php
index 43472324..5bc9e241 100644
--- a/tests/PhpWord/Shared/HtmlTest.php
+++ b/tests/PhpWord/Shared/HtmlTest.php
@@ -297,7 +297,7 @@ class HtmlTest extends AbstractWebServerEmbeddedTest
| header a |
- header b |
+ header b |
header c |
@@ -313,11 +313,17 @@ class HtmlTest extends AbstractWebServerEmbeddedTest
$this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc'));
$this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc'));
$this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val'));
+
//check border colors
- $this->assertEquals('#00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color'));
- $this->assertEquals('#00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color'));
- $this->assertEquals('#00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));
- $this->assertEquals('#00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color'));
+ $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:top', 'w:color'));
+ $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:right', 'w:color'));
+ $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));
+ $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:left', 'w:color'));
+
+ $this->assertEquals('00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color'));
+ $this->assertEquals('00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color'));
+ $this->assertEquals('00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));
+ $this->assertEquals('00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color'));
}
/**
@@ -595,4 +601,35 @@ class HtmlTest extends AbstractWebServerEmbeddedTest
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$this->assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:jc'));
}
+
+ /**
+ * Tests parsing hidden text
+ */
+ public function testParseHiddenText()
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $section = $phpWord->addSection();
+ $html = 'This is some hidden text.
';
+ Html::addHtml($section, $html);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:vanish'));
+ }
+
+ /**
+ * Tests parsing letter spacing
+ */
+ public function testParseLetterSpacing()
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $section = $phpWord->addSection();
+ $html = 'This is some text with letter spacing.
';
+ Html::addHtml($section, $html);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:spacing'));
+ $this->assertEquals(150 * 15, $doc->getElement('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')->getAttribute('w:val'));
+ }
}
From b3982ebb70d694080525adc860891094dddf14ac Mon Sep 17 00:00:00 2001
From: troosan
Date: Fri, 22 Feb 2019 22:06:30 +0100
Subject: [PATCH 21/53] fix documentation
---
src/PhpWord/Element/AbstractContainer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php
index 204d4a73..5e058667 100644
--- a/src/PhpWord/Element/AbstractContainer.php
+++ b/src/PhpWord/Element/AbstractContainer.php
@@ -31,7 +31,7 @@ namespace PhpOffice\PhpWord\Element;
* @method Footnote addFootnote(mixed $pStyle = null)
* @method Endnote addEndnote(mixed $pStyle = null)
* @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null)
- * @method Title addTitle(string $text, int $depth = 1)
+ * @method Title addTitle(mixed $text, int $depth = 1)
* @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9)
* @method PageBreak addPageBreak()
* @method Table addTable(mixed $style = null)
From 9958a4825fbe623ebf0dc16e831dc9fe9d7e8ff9 Mon Sep 17 00:00:00 2001
From: troosan
Date: Fri, 22 Feb 2019 22:06:54 +0100
Subject: [PATCH 22/53] allow other streams
---
src/PhpWord/Writer/AbstractWriter.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php
index 7e0d511a..2c1ad294 100644
--- a/src/PhpWord/Writer/AbstractWriter.php
+++ b/src/PhpWord/Writer/AbstractWriter.php
@@ -220,7 +220,7 @@ abstract class AbstractWriter implements WriterInterface
// Temporary file
$this->originalFilename = $filename;
- if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') {
+ if (strpos(strtolower($filename), 'php://') === 0) {
$filename = tempnam(Settings::getTempDir(), 'PhpWord');
if (false === $filename) {
$filename = $this->originalFilename; // @codeCoverageIgnore
From 81a1b2acffd55a47d94b372963404c425adc1eee Mon Sep 17 00:00:00 2001
From: Nick Winfield
Date: Sat, 23 Feb 2019 23:24:49 +0000
Subject: [PATCH 23/53] TrackChange doesn't handle all return types of
\DateTime::createFromFormat(...) (#1584)
* Added boolean check before setting the date
---
src/PhpWord/Element/TrackChange.php | 4 ++--
tests/PhpWord/Element/TrackChangeTest.php | 18 ++++++++++++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php
index 410ffb7c..91c221f2 100644
--- a/src/PhpWord/Element/TrackChange.php
+++ b/src/PhpWord/Element/TrackChange.php
@@ -58,13 +58,13 @@ class TrackChange extends AbstractContainer
*
* @param string $changeType
* @param string $author
- * @param null|int|\DateTime $date
+ * @param null|int|bool|\DateTime $date
*/
public function __construct($changeType = null, $author = null, $date = null)
{
$this->changeType = $changeType;
$this->author = $author;
- if ($date !== null) {
+ if ($date !== null && $date !== false) {
$this->date = ($date instanceof \DateTime) ? $date : new \DateTime('@' . $date);
}
}
diff --git a/tests/PhpWord/Element/TrackChangeTest.php b/tests/PhpWord/Element/TrackChangeTest.php
index df86feb2..b6cea924 100644
--- a/tests/PhpWord/Element/TrackChangeTest.php
+++ b/tests/PhpWord/Element/TrackChangeTest.php
@@ -41,4 +41,22 @@ class TrackChangeTest extends \PHPUnit\Framework\TestCase
$this->assertEquals($date, $oTrackChange->getDate());
$this->assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());
}
+
+ /**
+ * New instance with invalid \DateTime (produced by \DateTime::createFromFormat(...))
+ */
+ public function testConstructDefaultWithInvalidDate()
+ {
+ $author = 'Test User';
+ $date = false;
+ $oTrackChange = new TrackChange(TrackChange::INSERTED, $author, $date);
+
+ $oText = new Text('dummy text');
+ $oText->setTrackChange($oTrackChange);
+
+ $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TrackChange', $oTrackChange);
+ $this->assertEquals($author, $oTrackChange->getAuthor());
+ $this->assertEquals($date, null);
+ $this->assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());
+ }
}
From 81af913a66d7c508ad2337b2763cbd0c05e106de Mon Sep 17 00:00:00 2001
From: troosan
Date: Sun, 24 Feb 2019 21:23:59 +0100
Subject: [PATCH 24/53] Update CONTRIBUTING.md
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e62f2e6f..43ee0636 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,7 +6,7 @@ We want to create a high quality document writer and reader library that people
- **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement it right away. The world will be better with limitless innovations.
- **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, please, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please, use [PHPCodeSniffer](http://pear.php.net/package/PHP_CodeSniffer/) to validate your code against PSRs.
-- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.de/presentations.html) you can find PHPUnit best practices and additional information on effective unit testing, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life.
+- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.readthedocs.io) you can find documentation on how to write tests with PHPUnit, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life.
- **Request pull in separate branch**. Do not submit your request to the master branch. But create a separate branch named specifically for the issue that you addressed. Read [GitHub manual](https://help.github.com/articles/using-pull-requests) to find out more about this. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your Github Fork with the Branch of PHPWord.
That's it. Thank you for your interest in PHPWord, and welcome!
From 57ae7008b2fcd5941f2ddf487a13e9e2e616231d Mon Sep 17 00:00:00 2001
From: Maxim Bulygin
Date: Fri, 1 Mar 2019 16:31:47 +0200
Subject: [PATCH 25/53] add test to auto invert text color
---
tests/PhpWord/Writer/HTML/ElementTest.php | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php
index 90044b92..6ef02754 100644
--- a/tests/PhpWord/Writer/HTML/ElementTest.php
+++ b/tests/PhpWord/Writer/HTML/ElementTest.php
@@ -85,10 +85,10 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$section = $phpWord->addSection();
$table = $section->addTable();
$row1 = $table->addRow();
- $cell11 = $row1->addCell(1000, array('gridSpan' => 2));
+ $cell11 = $row1->addCell(1000, array('gridSpan' => 2, 'bgColor' => '6086B8'));
$cell11->addText('cell spanning 2 bellow');
$row2 = $table->addRow();
- $cell21 = $row2->addCell(500);
+ $cell21 = $row2->addCell(500, array('bgColor' => 'ffffff'));
$cell21->addText('first cell');
$cell22 = $row2->addCell(500);
$cell22->addText('second cell');
@@ -99,6 +99,11 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1);
$this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent);
$this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 2);
+
+ $this->assertEquals('#6086B8', $xpath->query('/html/body/table/tr[1]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent);
+ $this->assertEquals('#ffffff', $xpath->query('/html/body/table/tr[1]/td')->item(0)->attributes->getNamedItem('color')->textContent);
+ $this->assertEquals('#ffffff', $xpath->query('/html/body/table/tr[2]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent);
+ $this->assertNull($xpath->query('/html/body/table/tr[2]/td')->item(0)->attributes->getNamedItem('color'));
}
/**
From 014ff7d261ab1f5f1ca4cec396e24cec8d672bde Mon Sep 17 00:00:00 2001
From: Mykola Nicholas
Date: Wed, 13 Mar 2019 16:39:32 +0300
Subject: [PATCH 26/53] Added new constant to russian language
---
src/PhpWord/Style/Language.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php
index dd3ed819..98593394 100644
--- a/src/PhpWord/Style/Language.php
+++ b/src/PhpWord/Style/Language.php
@@ -70,6 +70,9 @@ final class Language extends AbstractStyle
const UK_UA = 'uk-UA';
const UK_UA_ID = 1058;
+
+ const RU_RU = 'ru-RU';
+ const RU_RU_ID = 1049;
/**
* Language ID, used for RTF document generation
From 607378b8fb694eca29a2560e653abad79ee5a76a Mon Sep 17 00:00:00 2001
From: Seamus Lee
Date: Sun, 24 Feb 2019 09:06:51 +1100
Subject: [PATCH 27/53] Ensure that entity_loader disable variable is re-set
back to the original setting
Simplify the setting of libxml_disable_entity_loader
---
src/PhpWord/Shared/Html.php | 3 ++-
src/PhpWord/TemplateProcessor.php | 3 ++-
tests/PhpWord/_includes/XmlDocument.php | 4 ++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 89881822..f2710ea1 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -72,7 +72,7 @@ class Html
}
// Load DOM
- libxml_disable_entity_loader(true);
+ $orignalLibEntityLoader = libxml_disable_entity_loader(true);
$dom = new \DOMDocument();
$dom->preserveWhiteSpace = $preserveWhiteSpace;
$dom->loadXML($html);
@@ -80,6 +80,7 @@ class Html
$node = $dom->getElementsByTagName('body');
self::parseNode($node->item(0), $element);
+ libxml_disable_entity_loader($orignalLibEntityLoader);
}
/**
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index 0f685bc4..7efc0f1a 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -170,7 +170,7 @@ class TemplateProcessor
*/
protected function transformSingleXml($xml, $xsltProcessor)
{
- libxml_disable_entity_loader(true);
+ $orignalLibEntityLoader = libxml_disable_entity_loader(true);
$domDocument = new \DOMDocument();
if (false === $domDocument->loadXML($xml)) {
throw new Exception('Could not load the given XML document.');
@@ -180,6 +180,7 @@ class TemplateProcessor
if (false === $transformedXml) {
throw new Exception('Could not transform the given XML document.');
}
+ libxml_disable_entity_loader($orignalLibEntityLoader);
return $transformedXml;
}
diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php
index f51eaad8..3a7869bc 100644
--- a/tests/PhpWord/_includes/XmlDocument.php
+++ b/tests/PhpWord/_includes/XmlDocument.php
@@ -76,10 +76,10 @@ class XmlDocument
$this->file = $file;
$file = $this->path . '/' . $file;
- libxml_disable_entity_loader(false);
+ $orignalLibEntityLoader = libxml_disable_entity_loader(false);
$this->dom = new \DOMDocument();
$this->dom->load($file);
- libxml_disable_entity_loader(true);
+ libxml_disable_entity_loader($orignalLibEntityLoader);
return $this->dom;
}
From 8cea3221dcca66a16420eee6966a8f6fd237f70c Mon Sep 17 00:00:00 2001
From: troosan
Date: Sun, 31 Mar 2019 13:20:51 +0200
Subject: [PATCH 28/53] remove trailing spaces
---
src/PhpWord/Style/Language.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php
index 98593394..18ef8897 100644
--- a/src/PhpWord/Style/Language.php
+++ b/src/PhpWord/Style/Language.php
@@ -70,7 +70,7 @@ final class Language extends AbstractStyle
const UK_UA = 'uk-UA';
const UK_UA_ID = 1058;
-
+
const RU_RU = 'ru-RU';
const RU_RU_ID = 1049;
From 2045e52db71c7e954c334dc28947a8756654e29f Mon Sep 17 00:00:00 2001
From: arthur
Date: Tue, 9 Apr 2019 10:55:43 +0200
Subject: [PATCH 29/53] call static instead of self on protected method
---
src/PhpWord/Shared/Html.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index f2710ea1..c484e08f 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -192,7 +192,7 @@ class Html
$newElement = $element;
}
- self::parseChildNodes($node, $newElement, $styles, $data);
+ static::parseChildNodes($node, $newElement, $styles, $data);
}
/**
From c00c77c4c1e3f1c1fc9e2d4bc2ecd7fdb8fa4083 Mon Sep 17 00:00:00 2001
From: Nicolas Dermine
Date: Wed, 17 Apr 2019 18:27:33 +0200
Subject: [PATCH 30/53] fix typo in changelog
---
CHANGELOG.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9ec1deef..66271bae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@ v0.17.0 (?? ??? 2019)
### Fixed
- Fix HTML border-color parsing. @troosan #1551 #1570
-### Miscelaneous
+### Miscellaneous
- Use embedded http server to test loading of remote images @troosan #
v0.16.0 (30 dec 2018)
@@ -40,7 +40,7 @@ v0.16.0 (30 dec 2018)
- For RTF writers, sizes should should never have decimals @Samuel-BF #1536
- Style Name Parsing fails if document generated by a non-english word version @begnini #1434
-### Miscelaneous
+### Miscellaneous
- Get rid of duplicated code in TemplateProcessor @abcdmitry #1161
v0.15.0 (14 Jul 2018)
@@ -86,7 +86,7 @@ v0.15.0 (14 Jul 2018)
- Remove zend-stdlib dependency @Trainmaster #1284
- The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`.
-### Miscelaneous
+### Miscellaneous
- Drop GitHub pages, switch to coveralls for code coverage analysis @czosel #1360
v0.14.0 (29 Dec 2017)
From 18b3c754ef32f5a2c0fc21666ffe481da370cf97 Mon Sep 17 00:00:00 2001
From: Walter Tamboer
Date: Thu, 9 May 2019 15:29:25 +0200
Subject: [PATCH 31/53] No nested w:pPr elements in ListItemRun.
This commit fixes issue #1529
This commit prevents nested w:pPr elements when using a ListItemRun with
a paragraph style. The different between a ListItem and a ListItem run
is that the setWithoutPPR method is called on the ParagraphStyleWriter
(PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph).
According to the specs it's not allowed to have nested w:pPr elements.
See http://www.datypic.com/sc/ooxml/e-w_pPr-2.html
---
.../Writer/Word2007/Element/ListItemRun.php | 59 +++++++++++++------
1 file changed, 41 insertions(+), 18 deletions(-)
diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php
index 765d2ee0..fda2b078 100644
--- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php
+++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php
@@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Writer\Word2007\Element;
+use PhpOffice\PhpWord\Element\ListItemRun as ListItemRunElement;
use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter;
/**
@@ -31,34 +32,56 @@ class ListItemRun extends AbstractElement
*/
public function write()
{
- $xmlWriter = $this->getXmlWriter();
$element = $this->getElement();
- if (!$element instanceof \PhpOffice\PhpWord\Element\ListItemRun) {
+
+ if (!$element instanceof ListItemRunElement) {
return;
}
+ $this->writeParagraph($element);
+ }
+
+ private function writeParagraph(ListItemRunElement $element)
+ {
+ $xmlWriter = $this->getXmlWriter();
$xmlWriter->startElement('w:p');
- $xmlWriter->startElement('w:pPr');
- $paragraphStyle = $element->getParagraphStyle();
- $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle);
- $styleWriter->setIsInline(true);
- $styleWriter->write();
-
- $xmlWriter->startElement('w:numPr');
- $xmlWriter->startElement('w:ilvl');
- $xmlWriter->writeAttribute('w:val', $element->getDepth());
- $xmlWriter->endElement(); // w:ilvl
- $xmlWriter->startElement('w:numId');
- $xmlWriter->writeAttribute('w:val', $element->getStyle()->getNumId());
- $xmlWriter->endElement(); // w:numId
- $xmlWriter->endElement(); // w:numPr
-
- $xmlWriter->endElement(); // w:pPr
+ $this->writeParagraphProperties($element);
$containerWriter = new Container($xmlWriter, $element);
$containerWriter->write();
$xmlWriter->endElement(); // w:p
}
+
+ private function writeParagraphProperties(ListItemRunElement $element)
+ {
+ $xmlWriter = $this->getXmlWriter();
+ $xmlWriter->startElement('w:pPr');
+
+ $styleWriter = new ParagraphStyleWriter($xmlWriter, $element->getParagraphStyle());
+ $styleWriter->setIsInline(true);
+ $styleWriter->setWithoutPPR(true);
+ $styleWriter->write();
+
+ $this->writeParagraphPropertiesNumbering($element);
+
+ $xmlWriter->endElement(); // w:pPr
+ }
+
+ private function writeParagraphPropertiesNumbering(ListItemRunElement $element)
+ {
+ $xmlWriter = $this->getXmlWriter();
+ $xmlWriter->startElement('w:numPr');
+
+ $xmlWriter->writeElementBlock('w:ilvl', array(
+ 'w:val' => $element->getDepth(),
+ ));
+
+ $xmlWriter->writeElementBlock('w:numId', array(
+ 'w:val' => $element->getStyle()->getNumId(),
+ ));
+
+ $xmlWriter->endElement(); // w:numPr
+ }
}
From b209fec72bd277c0452d4f5891c31f320612dc2a Mon Sep 17 00:00:00 2001
From: Nishant Bhatt
Date: Mon, 3 Jun 2019 15:44:10 +0200
Subject: [PATCH 32/53] To suport preseve text inside sub container
if we use preseve text inside table, issue fix
https://stackoverflow.com/questions/33070424/phpword-cannot-add-preservetext-in-section
---
src/PhpWord/Element/AbstractContainer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php
index 204d4a73..74aabb19 100644
--- a/src/PhpWord/Element/AbstractContainer.php
+++ b/src/PhpWord/Element/AbstractContainer.php
@@ -254,7 +254,7 @@ abstract class AbstractContainer extends AbstractElement
// Special condition, e.g. preservetext can only exists in cell when
// the cell is located in header or footer
$validSubcontainers = array(
- 'PreserveText' => array(array('Cell'), array('Header', 'Footer')),
+ 'PreserveText' => array(array('Cell'), array('Header', 'Footer', 'Section')),
'Footnote' => array(array('Cell', 'TextRun'), array('Section')),
'Endnote' => array(array('Cell', 'TextRun'), array('Section')),
);
From 3c6a1a1568602b90589c108ac748d98f6f022a23 Mon Sep 17 00:00:00 2001
From: troosan
Date: Thu, 13 Jun 2019 23:03:09 +0200
Subject: [PATCH 33/53] add unit test
---
tests/PhpWord/Writer/Word2007/ElementTest.php | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php
index 703f4590..6a295965 100644
--- a/tests/PhpWord/Writer/Word2007/ElementTest.php
+++ b/tests/PhpWord/Writer/Word2007/ElementTest.php
@@ -510,4 +510,25 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
$this->assertEquals('this text contains an & (ampersant)', $doc->getElement('/w:document/w:body/w:p/w:r/w:t')->nodeValue);
}
+
+ /**
+ * Test ListItemRun paragraph style writing
+ */
+ public function testListItemRunStyleWriting()
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addParagraphStyle('MyParagraphStyle', array('spaceBefore' => 400));
+
+ $section = $phpWord->addSection();
+ $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle');
+ $listItemRun->addText('List item');
+ $listItemRun->addText(' in bold', array('bold' => true));
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ $this->assertFalse($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pPr'));
+ $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle'));
+ $this->assertEquals('List item', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue);
+ $this->assertEquals(' in bold', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue);
+ $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r[2]/w:rPr/w:b'));
+ }
}
From d7ed18c39db077aeb212598c1216a0068867296e Mon Sep 17 00:00:00 2001
From: troosan
Date: Fri, 14 Jun 2019 00:19:44 +0200
Subject: [PATCH 34/53] fix test
---
tests/PhpWord/Element/CellTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php
index d4aaa488..db0bae5c 100644
--- a/tests/PhpWord/Element/CellTest.php
+++ b/tests/PhpWord/Element/CellTest.php
@@ -231,7 +231,7 @@ class CellTest extends \PHPUnit\Framework\TestCase
public function testAddPreserveTextException()
{
$oCell = new Cell();
- $oCell->setDocPart('Section', 1);
+ $oCell->setDocPart('TextRun', 1);
$oCell->addPreserveText('text');
}
From d6b0977afe8922bb720cdcee5d3b91f97a1e537e Mon Sep 17 00:00:00 2001
From: Brandon Frohs
Date: Mon, 1 Jul 2019 13:09:36 -0400
Subject: [PATCH 35/53] Add issue templates for bug reports, feature requests,
and usage questions
---
.github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++
.github/ISSUE_TEMPLATE/feature_request.md | 22 +++++++++++++
.github/ISSUE_TEMPLATE/how-to-use.md | 14 +++++++++
3 files changed, 74 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
create mode 100644 .github/ISSUE_TEMPLATE/how-to-use.md
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..fcb3a65d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help improve PHPWord
+labels: Bug Report
+
+---
+
+### Describe the Bug
+
+A clear and concise description of what the bug is.
+
+### Steps to Reproduce
+
+Please provide a code sample that reproduces the issue.
+
+```php
+addSection();
+$section->...
+```
+
+### Expected Behavior
+
+A clear and concise description of what you expected to happen.
+
+### Current Behavior
+
+What is the current behavior?
+
+### Context
+
+Please fill in your environment information:
+
+- PHP Version:
+- PHPWord Version:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..171e8378
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,22 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+labels: Change Request
+
+---
+
+### Is your feature request related to a problem? Please describe.
+
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+### Describe the solution you'd like
+
+A clear and concise description of what you want to happen.
+
+### Describe alternatives you've considered
+
+A clear and concise description of any alternative solutions or features you've considered.
+
+### Additional context
+
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/how-to-use.md b/.github/ISSUE_TEMPLATE/how-to-use.md
new file mode 100644
index 00000000..0fef996b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/how-to-use.md
@@ -0,0 +1,14 @@
+---
+name: How to Use PHPWord
+about: Find out how to use PHPWord
+labels: WontFix
+
+---
+
+***Please do not use the issue tracker to ask how to use PHPWord.***
+
+Documentation is available on [Read the Docs](https://phpword.readthedocs.io/en/latest/).
+
+Sample code is in the [`/samples/` directory](https://github.com/PHPOffice/PHPWord/tree/develop/samples).
+
+Usage questions belong on [Stack Overflow](https://stackoverflow.com/questions/tagged/phpword).
From e401adeb7e2f8e6efbbd6bd5b50807ee6863d5b8 Mon Sep 17 00:00:00 2001
From: Brandon Frohs
Date: Mon, 1 Jul 2019 13:10:55 -0400
Subject: [PATCH 36/53] Update CONTRIBUTING to match reality and account for
new issue templates
---
CONTRIBUTING.md | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 43ee0636..dbef13a6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,13 +1,30 @@
# Contributing to PHPWord
-PHPWord is built by the crowd and for the crowd. Every contribution is welcome; either by [submitting](https://github.com/PHPOffice/PHPWord/issues) bug issues or suggesting improvements, or in a more active form like [requesting](https://github.com/PHPOffice/PHPWord/pulls) a pull.
+PHPWord is built by the crowd and for the crowd. Every contribution is welcome; either by [reporting a bug](https://github.com/PHPOffice/PHPWord/issues/new?labels=Bug+Report&template=bug_report.md) or [suggesting improvements](https://github.com/PHPOffice/PHPWord/issues/new?labels=Change+Request&template=feature_request.md), or in a more active form like [requesting a pull](https://github.com/PHPOffice/PHPWord/pulls).
-We want to create a high quality document writer and reader library that people can use with more confidence and less bugs. We want to collaborate happily, code joyfully, and get alive merrily. Thus, below are some guidelines, that we expect to be followed by each contributor.
+We want to create a high quality document writer and reader library that people can use with more confidence and fewer bugs. We want to collaborate happily, code joyfully, and live merrily. Thus, below are some guidelines that we expect to be followed by each contributor:
-- **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement it right away. The world will be better with limitless innovations.
-- **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, please, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please, use [PHPCodeSniffer](http://pear.php.net/package/PHP_CodeSniffer/) to validate your code against PSRs.
-- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.readthedocs.io) you can find documentation on how to write tests with PHPUnit, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life.
-- **Request pull in separate branch**. Do not submit your request to the master branch. But create a separate branch named specifically for the issue that you addressed. Read [GitHub manual](https://help.github.com/articles/using-pull-requests) to find out more about this. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your Github Fork with the Branch of PHPWord.
+- **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement them right away. The world will be better with limitless innovations.
+- **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please run `composer fix` to automatically fix your code to match these recommendations.
+- **Test your code**. No one knows your code better than you, so we depend on you to test the changes you make before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and request that you use this tool too. Tests can be ran with `composer test`. [Documentation for writing tests with PHPUnit is available on Read the Docs.](https://phpunit.readthedocs.io)
+- **Use best practices when submitting pull requests**. Create a separate branch named specifically for the issue that you are addressing. Read the [GitHub manual](https://help.github.com/articles/about-pull-requests) to learn more about pull requests and GitHub. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your fork on GitHub with the upstream branch from PHPWord.
+
+## Getting Started
+
+1. [Clone](https://help.github.com/en/articles/cloning-a-repository) [PHPWord](https://github.com/PHPOffice/PHPWord/)
+2. [Install Composer](https://getcomposer.org/download/) if you don't already have it
+3. Open your terminal and:
+ 1. Switch to the directory PHPWord was cloned to (e.g., `cd ~/Projects/PHPWord/`)
+ 2. Run `composer install` to install the dependencies
+
+You're ready to start working on PHPWord! Tests belong in the `/tests/PhpWord/` directory, the source code is in `/src/PhpWord/`, and any documentation should go in `/docs/`. Familiarize yourself with the codebase and try your hand at fixing [one of our outstanding issues](https://github.com/PHPOffice/PHPWord/issues). Before you get started, check the [existing pull requests](https://github.com/PHPOffice/PHPWord/pulls) to make sure no one else is already working on it.
+
+Once you have an issue you want to start working on, you'll need to write tests for it, and then you can start implementing the changes necessary to pass the new tests. To run the tests, you can run one of the following commands in your terminal:
+
+- `composer test-no-coverage` to run all of the tests
+- `composer test` to run all of the tests and generate test coverage reports
+
+When you're ready to submit your new (and fully tested) feature, [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new).
That's it. Thank you for your interest in PHPWord, and welcome!
From 74e52ce71be3ab1fa1703c28cb2989a4df44dbbb Mon Sep 17 00:00:00 2001
From: Brandon Frohs
Date: Mon, 1 Jul 2019 13:33:48 -0400
Subject: [PATCH 37/53] Remove the existing issue template
---
docs/ISSUE_TEMPLATE.md | 35 -----------------------------------
1 file changed, 35 deletions(-)
delete mode 100644 docs/ISSUE_TEMPLATE.md
diff --git a/docs/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md
deleted file mode 100644
index c7ed27d7..00000000
--- a/docs/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,35 +0,0 @@
-This is:
-
-- [ ] a bug report
-- [ ] a feature request
-- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpword)
-
-### Expected Behavior
-
-Please describe the behavior you are expecting.
-
-### Current Behavior
-
-What is the current behavior?
-
-### Failure Information
-
-Please help provide information about the failure.
-
-### How to Reproduce
-
-Please provide a code sample that reproduces the issue.
-
-```php
-addSection();
-$section->...
-```
-
-### Context
-
-* PHP version:
-* PHPWord version: 0.14
From 71ac081cfa3cfc38bb8007dd195bba5fda12e80f Mon Sep 17 00:00:00 2001
From: Brandon Frohs
Date: Mon, 1 Jul 2019 13:34:05 -0400
Subject: [PATCH 38/53] Add note about using `composer check` before submitting
pull requests
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dbef13a6..ac262a0f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,7 +24,7 @@ Once you have an issue you want to start working on, you'll need to write tests
- `composer test-no-coverage` to run all of the tests
- `composer test` to run all of the tests and generate test coverage reports
-When you're ready to submit your new (and fully tested) feature, [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new).
+When you're ready to submit your new (and fully tested) feature, ensure `composer check` passes and [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new).
That's it. Thank you for your interest in PHPWord, and welcome!
From b13aa70ae9d451b8e6e6b049cbc11367fd90c0b6 Mon Sep 17 00:00:00 2001
From: Brandon Frohs
Date: Mon, 1 Jul 2019 13:36:41 -0400
Subject: [PATCH 39/53] Move pull request template to avoid confusion
---
{docs => .github}/PULL_REQUEST_TEMPLATE.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename {docs => .github}/PULL_REQUEST_TEMPLATE.md (100%)
diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
similarity index 100%
rename from docs/PULL_REQUEST_TEMPLATE.md
rename to .github/PULL_REQUEST_TEMPLATE.md
From 9abf4473b0e0411c443f885d2f8fe6b99a553537 Mon Sep 17 00:00:00 2001
From: Mario
Date: Tue, 2 Jul 2019 16:02:52 +0200
Subject: [PATCH 40/53] Update Wrong definition
---
src/PhpWord/Element/AbstractContainer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php
index 5e058667..abf23c6e 100644
--- a/src/PhpWord/Element/AbstractContainer.php
+++ b/src/PhpWord/Element/AbstractContainer.php
@@ -41,7 +41,7 @@ namespace PhpOffice\PhpWord\Element;
* @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null)
* @method Line addLine(mixed $lineStyle = null)
* @method Shape addShape(string $type, mixed $style = null)
- * @method Chart addChart(string $type, array $categories, array $values, array $style = null)
+ * @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null)
* @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)
* @method SDT addSDT(string $type)
*
From 9e93d5eae5e544e5c280a471eb959808d1eac0db Mon Sep 17 00:00:00 2001
From: Andrew Busel
Date: Wed, 3 Jul 2019 19:24:15 +0300
Subject: [PATCH 41/53] Update Html.php
---
src/PhpWord/Shared/Html.php | 50 ++++++++++++++++++-------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index c484e08f..1dd13072 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -28,13 +28,13 @@ use PhpOffice\PhpWord\Style\Paragraph;
/**
* Common Html functions
*
- * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
+ * @SuppressWarnings(PHPMD.UnusedprotectedMethod) For readWPNode
*/
class Html
{
- private static $listIndex = 0;
- private static $xpath;
- private static $options;
+ protected static $listIndex = 0;
+ protected static $xpath;
+ protected static $options;
/**
* Add HTML parts.
@@ -203,7 +203,7 @@ class Html
* @param array $styles
* @param array $data
*/
- private static function parseChildNodes($node, $element, $styles, $data)
+ protected static function parseChildNodes($node, $element, $styles, $data)
{
if ('li' != $node->nodeName) {
$cNodes = $node->childNodes;
@@ -225,7 +225,7 @@ class Html
* @param array &$styles
* @return \PhpOffice\PhpWord\Element\TextRun
*/
- private static function parseParagraph($node, $element, &$styles)
+ protected static function parseParagraph($node, $element, &$styles)
{
$styles['paragraph'] = self::recursiveParseStylesInHierarchy($node, $styles['paragraph']);
$newElement = $element->addTextRun($styles['paragraph']);
@@ -244,7 +244,7 @@ class Html
* @todo Think of a clever way of defining header styles, now it is only based on the assumption, that
* Heading1 - Heading6 are already defined somewhere
*/
- private static function parseHeading($element, &$styles, $argument1)
+ protected static function parseHeading($element, &$styles, $argument1)
{
$styles['paragraph'] = $argument1;
$newElement = $element->addTextRun($styles['paragraph']);
@@ -259,7 +259,7 @@ class Html
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
* @param array &$styles
*/
- private static function parseText($node, $element, &$styles)
+ protected static function parseText($node, $element, &$styles)
{
$styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']);
@@ -280,7 +280,7 @@ class Html
* @param string $argument1 Style name
* @param string $argument2 Style value
*/
- private static function parseProperty(&$styles, $argument1, $argument2)
+ protected static function parseProperty(&$styles, $argument1, $argument2)
{
$styles['font'][$argument1] = $argument2;
}
@@ -291,7 +291,7 @@ class Html
* @param \DOMNode $node
* @param array &$styles
*/
- private static function parseSpan($node, &$styles)
+ protected static function parseSpan($node, &$styles)
{
self::parseInlineStyle($node, $styles['font']);
}
@@ -306,7 +306,7 @@ class Html
*
* @todo As soon as TableItem, RowItem and CellItem support relative width and height
*/
- private static function parseTable($node, $element, &$styles)
+ protected static function parseTable($node, $element, &$styles)
{
$elementStyles = self::parseInlineStyle($node, $styles['table']);
@@ -335,7 +335,7 @@ class Html
* @param array &$styles
* @return Row $element
*/
- private static function parseRow($node, $element, &$styles)
+ protected static function parseRow($node, $element, &$styles)
{
$rowStyles = self::parseInlineStyle($node, $styles['row']);
if ($node->parentNode->nodeName == 'thead') {
@@ -353,7 +353,7 @@ class Html
* @param array &$styles
* @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element
*/
- private static function parseCell($node, $element, &$styles)
+ protected static function parseCell($node, $element, &$styles)
{
$cellStyles = self::recursiveParseStylesInHierarchy($node, $styles['cell']);
@@ -376,7 +376,7 @@ class Html
* @param \DOMNode $node
* @return bool Returns true if the node contains an HTML element that cannot be added to TextRun
*/
- private static function shouldAddTextRun(\DOMNode $node)
+ protected static function shouldAddTextRun(\DOMNode $node)
{
$containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol', $node)->length > 0;
if ($containsBlockElement) {
@@ -393,7 +393,7 @@ class Html
* @param \DOMNode $node
* @param array &$styles
*/
- private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style)
+ protected static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style)
{
$parentStyle = self::parseInlineStyle($node, array());
$style = array_merge($parentStyle, $style);
@@ -412,7 +412,7 @@ class Html
* @param array &$styles
* @param array &$data
*/
- private static function parseList($node, $element, &$styles, &$data)
+ protected static function parseList($node, $element, &$styles, &$data)
{
$isOrderedList = $node->nodeName === 'ol';
if (isset($data['listdepth'])) {
@@ -431,7 +431,7 @@ class Html
* @param bool $isOrderedList
* @return array
*/
- private static function getListStyle($isOrderedList)
+ protected static function getListStyle($isOrderedList)
{
if ($isOrderedList) {
return array(
@@ -477,7 +477,7 @@ class Html
* @todo This function is almost the same like `parseChildNodes`. Merged?
* @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes
*/
- private static function parseListItem($node, $element, &$styles, $data)
+ protected static function parseListItem($node, $element, &$styles, $data)
{
$cNodes = $node->childNodes;
if (!empty($cNodes)) {
@@ -495,7 +495,7 @@ class Html
* @param array $styles
* @return array
*/
- private static function parseStyle($attribute, $styles)
+ protected static function parseStyle($attribute, $styles)
{
$properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;"));
@@ -623,7 +623,7 @@ class Html
*
* @return \PhpOffice\PhpWord\Element\Image
**/
- private static function parseImage($node, $element)
+ protected static function parseImage($node, $element)
{
$style = array();
$src = null;
@@ -726,7 +726,7 @@ class Html
* @param string $cssBorderStyle
* @return null|string
*/
- private static function mapBorderStyle($cssBorderStyle)
+ protected static function mapBorderStyle($cssBorderStyle)
{
switch ($cssBorderStyle) {
case 'none':
@@ -739,7 +739,7 @@ class Html
}
}
- private static function mapBorderColor(&$styles, $cssBorderColor)
+ protected static function mapBorderColor(&$styles, $cssBorderColor)
{
$numColors = substr_count($cssBorderColor, '#');
if ($numColors === 1) {
@@ -759,7 +759,7 @@ class Html
* @param string $cssAlignment
* @return string|null
*/
- private static function mapAlign($cssAlignment)
+ protected static function mapAlign($cssAlignment)
{
switch ($cssAlignment) {
case 'right':
@@ -778,7 +778,7 @@ class Html
*
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
*/
- private static function parseLineBreak($element)
+ protected static function parseLineBreak($element)
{
$element->addTextBreak();
}
@@ -790,7 +790,7 @@ class Html
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
* @param array $styles
*/
- private static function parseLink($node, $element, &$styles)
+ protected static function parseLink($node, $element, &$styles)
{
$target = null;
foreach ($node->attributes as $attribute) {
From 415bdb378dbfbd50e12338b0ae898e5e8fe55fb1 Mon Sep 17 00:00:00 2001
From: Andrew Busel
Date: Wed, 3 Jul 2019 19:25:29 +0300
Subject: [PATCH 42/53] Update Html.php
---
src/PhpWord/Shared/Html.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 1dd13072..54e9509e 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -28,7 +28,7 @@ use PhpOffice\PhpWord\Style\Paragraph;
/**
* Common Html functions
*
- * @SuppressWarnings(PHPMD.UnusedprotectedMethod) For readWPNode
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
*/
class Html
{
From 4f7790baab33bf70dc48b02ca838a2dcac21c849 Mon Sep 17 00:00:00 2001
From: Manuel Transfeld
Date: Tue, 9 Jul 2019 17:22:30 +0200
Subject: [PATCH 43/53] Fix link anchor
Fix a typo in a link
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f1d1d6ee..68092a48 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ PHPWord requires the following:
## Installation
PHPWord is installed via [Composer](https://getcomposer.org/).
-To [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links>) to PHPWord in your project, either
+To [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links) to PHPWord in your project, either
Run the following to use the latest stable version
```sh
From 5f8fad39858be572cca0a3ff16cd582d4e5938e9 Mon Sep 17 00:00:00 2001
From: Brandon Frohs
Date: Thu, 11 Jul 2019 17:14:35 -0400
Subject: [PATCH 44/53] Use relative links in README to ensure they go to the
correct branch
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 68092a48..b15f83d7 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Develop:
PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF.
-PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/).
+PHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/).
If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword)
@@ -174,7 +174,7 @@ You can also read the [Developers' Documentation](http://phpword.readthedocs.org
We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute.
-- Read [our contributing guide](https://github.com/PHPOffice/PHPWord/blob/master/CONTRIBUTING.md).
+- Read [our contributing guide](CONTRIBUTING.md).
- [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [develop](https://github.com/PHPOffice/PHPWord/tree/develop) branch.
- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub.
- Follow [@PHPWord](https://twitter.com/PHPWord) and [@PHPOffice](https://twitter.com/PHPOffice) on Twitter.
From 5fe485adac3c48c031377451ea94814b7cc95800 Mon Sep 17 00:00:00 2001
From: Andrey Bolonin
Date: Sun, 14 Jul 2019 15:26:23 +0300
Subject: [PATCH 45/53] add php 7.4snapshot
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index 1d32cfda..806a5f57 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,7 @@ php:
- 7.1
- 7.2
- 7.3
+ - 7.4snapshot
matrix:
include:
From 41227e8e08f6bb8d56f201a8ab250d9ed1eb6317 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Dupont?=
Date: Wed, 28 Aug 2019 10:59:06 +0200
Subject: [PATCH 46/53] Fix apt-get crash in Travis CI
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index 1d32cfda..802f3229 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -36,6 +36,7 @@ env:
before_install:
## Packages
+ - sudo rm -f /etc/apt/sources.list.d/mongodb.list # Makes apt crash on Precise, and we don't need MongoDB
- sudo apt-get update -qq
- sudo apt-get install -y graphviz
From 72311767c5c6ac184c7a5bbb210d76dd88ccb3bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Dupont?=
Date: Wed, 28 Aug 2019 11:11:19 +0200
Subject: [PATCH 47/53] Fix Travis crash with Composer memory usage
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 802f3229..d3b1f907 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@ matrix:
- php: 7.0
env: COVERAGE=1
- php: 5.3
- env: COMPOSER_MEMORY_LIMIT=2G
+ env: COMPOSER_MEMORY_LIMIT=3G
- php: 7.3
env: DEPENDENCIES="--ignore-platform-reqs"
exclude:
From 18ec5d63f379ff1b020901c8eb2e0ee0eab22690 Mon Sep 17 00:00:00 2001
From: troosan
Date: Sun, 1 Sep 2019 21:03:22 +0200
Subject: [PATCH 48/53] fix phpmd config
---
phpmd.xml.dist | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/phpmd.xml.dist b/phpmd.xml.dist
index 44b3efdf..2077e02b 100644
--- a/phpmd.xml.dist
+++ b/phpmd.xml.dist
@@ -19,7 +19,7 @@
-
+
From e9a4251c7e5b6b15bd4f0008f0a59b5bc8d44ace Mon Sep 17 00:00:00 2001
From: troosan
Date: Sun, 1 Sep 2019 21:54:28 +0200
Subject: [PATCH 49/53] Use precise only for php 5.3
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 806a5f57..b689506c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: php
-dist: precise
+dist: xenial
php:
- 5.3
@@ -18,6 +18,7 @@ matrix:
- php: 7.0
env: COVERAGE=1
- php: 5.3
+ dist: precise
env: COMPOSER_MEMORY_LIMIT=2G
- php: 7.3
env: DEPENDENCIES="--ignore-platform-reqs"
From aec9582d835d3dc30a0dbdaf95cb11d9ccf2cb4e Mon Sep 17 00:00:00 2001
From: troosan
Date: Sun, 1 Sep 2019 22:12:34 +0200
Subject: [PATCH 50/53] allow php 7.4 build to fail
---
.travis.yml | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 8c3cd86a..acdf95cc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,17 +15,25 @@ php:
matrix:
include:
- - php: 7.0
- env: COVERAGE=1
- php: 5.3
dist: precise
env: COMPOSER_MEMORY_LIMIT=3G
+ - php: 5.4
+ dist: trusty
+ - php: 5.5
+ dist: trusty
+ - php: 7.0
+ env: COVERAGE=1
- php: 7.3
env: DEPENDENCIES="--ignore-platform-reqs"
exclude:
- php: 5.3
+ - php: 5.4
+ - php: 5.5
- php: 7.0
- php: 7.3
+ allow_failures:
+ - php: 7.4snapshot
cache:
directories:
From 8f4f4dcd4840f4a1bfee768bc26a998c532cbb3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franti=C5=A1ek=20Ma=C5=A1a?=
Date: Mon, 2 Sep 2019 18:13:10 +0200
Subject: [PATCH 51/53] Added return type
---
src/PhpWord/Element/AbstractElement.php | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php
index e3e54ed4..46372b71 100644
--- a/src/PhpWord/Element/AbstractElement.php
+++ b/src/PhpWord/Element/AbstractElement.php
@@ -96,7 +96,7 @@ abstract class AbstractElement
/**
* A reference to the parent
*
- * @var \PhpOffice\PhpWord\Element\AbstractElement
+ * @var AbstractElement|null
*/
private $parent;
@@ -335,6 +335,11 @@ abstract class AbstractElement
$this->commentRangeEnd->setEndElement($this);
}
+ /**
+ * Get parent element
+ *
+ * @return AbstractElement|null
+ */
public function getParent()
{
return $this->parent;
From 7628b41fdfa03a0fc499936ba41d280ebdad9146 Mon Sep 17 00:00:00 2001
From: Samuel BF <36996277+Samuel-BF@users.noreply.github.com>
Date: Sat, 7 Sep 2019 21:55:33 +0200
Subject: [PATCH 52/53] Add support for basic fields in RTF writer.
---
src/PhpWord/Writer/RTF/Element/Field.php | 80 ++++++++++++++++++++++++
tests/PhpWord/Writer/RTF/ElementTest.php | 38 ++++++++++-
2 files changed, 117 insertions(+), 1 deletion(-)
create mode 100644 src/PhpWord/Writer/RTF/Element/Field.php
diff --git a/src/PhpWord/Writer/RTF/Element/Field.php b/src/PhpWord/Writer/RTF/Element/Field.php
new file mode 100644
index 00000000..e958e9de
--- /dev/null
+++ b/src/PhpWord/Writer/RTF/Element/Field.php
@@ -0,0 +1,80 @@
+element;
+ if (!$element instanceof \PhpOffice\PhpWord\Element\Field) {
+ return;
+ }
+
+ $this->getStyles();
+
+ $content = '';
+ $content .= $this->writeOpening();
+ $content .= '{';
+ $content .= $this->writeFontStyle();
+
+ $methodName = 'write' . ucfirst(strtolower($element->getType()));
+ if (!method_exists($this, $methodName)) {
+ // Unsupported field
+ $content .= '';
+ } else {
+ $content .= '\\field{\\*\\fldinst ';
+ $content .= $this->$methodName($element);
+ $content .= '}{\\fldrslt}';
+ }
+ $content .= '}';
+ $content .= $this->writeClosing();
+
+ return $content;
+ }
+
+ protected function writePage()
+ {
+ return 'PAGE';
+ }
+
+ protected function writeNumpages()
+ {
+ return 'NUMPAGES';
+ }
+
+ protected function writeDate(\PhpOffice\PhpWord\Element\Field $element)
+ {
+ $content = '';
+ $content .= 'DATE';
+ $properties = $element->getProperties();
+ if (isset($properties['dateformat'])) {
+ $content .= ' \\\\@ "' . $properties['dateformat'] . '"';
+ }
+
+ return $content;
+ }
+}
diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php
index 47630335..4b01bacf 100644
--- a/tests/PhpWord/Writer/RTF/ElementTest.php
+++ b/tests/PhpWord/Writer/RTF/ElementTest.php
@@ -29,7 +29,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
*/
public function testUnmatchedElements()
{
- $elements = array('Container', 'Text', 'Title', 'Link', 'Image', 'Table');
+ $elements = array('Container', 'Text', 'Title', 'Link', 'Image', 'Table', 'Field');
foreach ($elements as $element) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $element;
$parentWriter = new RTF();
@@ -39,4 +39,40 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$this->assertEquals('', $object->write());
}
}
+
+ public function testPageField()
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('PAGE');
+ $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element);
+
+ $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $field->write());
+ }
+
+ public function testNumpageField()
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES');
+ $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element);
+
+ $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $field->write());
+ }
+
+ public function testDateField()
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('DATE', array('dateformat' => 'd MM yyyy H:mm:ss'));
+ $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element);
+
+ $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $field->write());
+ }
+
+ public function testIndexField()
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('INDEX');
+ $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element);
+
+ $this->assertEquals("{}\\par\n", $field->write());
+ }
}
From b8346af548d399acd9e30fc76ab0c55c2fec03a5 Mon Sep 17 00:00:00 2001
From: troosan
Date: Tue, 1 Oct 2019 22:43:33 +0200
Subject: [PATCH 53/53] update changelog for version 0.17
---
CHANGELOG.md | 21 ++++++++++++++++++---
composer.json | 2 +-
docs/conf.py | 2 +-
docs/installing.rst | 2 +-
4 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66271bae..5d55fa2b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,18 +3,33 @@ Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
-v0.17.0 (?? ??? 2019)
+v0.17.0 (01 oct 2019)
----------------------
### Added
-- Add RightToLeft table presentation. @troosan #1550
+- Add methods setValuesFromArray and cloneRowFromArray to the TemplateProcessor @geraldb-nicat #670
- Set complex type in template @troosan #1565
+- implement support for section vAlign @troosan #1569
+- ParseStyle for border-color @Gllrm0 #1551
+- Html writer auto invert text color @SailorMax #1387
+- Add RightToLeft table presentation. @troosan #1550
- Add support for page vertical alignment. @troosan #672 #1569
+- Adding setNumId method for ListItem style @eweso #1329
+- Add support for basic fields in RTF writer. @Samuel-BF #1717
### Fixed
- Fix HTML border-color parsing. @troosan #1551 #1570
+- Language::validateLocale should pass with locale 'zxx'. @efpapado #1558
+- can't align center vertically with the text @ter987 #672
+- fix parsing of border-color and add test @troosan #1570
+- TrackChange doesn't handle all return types of \DateTime::createFromFormat(...) @superhaggis #1584
+- To support PreserveText inside sub container @bhattnishant #1637
+- No nested w:pPr elements in ListItemRun. @waltertamboer #1628
+- Ensure that entity_loader disable variable is re-set back to the original setting @seamuslee001 #1585
### Miscellaneous
-- Use embedded http server to test loading of remote images @troosan #
+- Use embedded http server to test loading of remote images @troosan #1544
+- Change private to protected to be able extending class Html @SpinyMan #1646
+- Fix apt-get crash in Travis CI for PHP 5.3 @mdupont #1707
v0.16.0 (30 dec 2018)
----------------------
diff --git a/composer.json b/composer.json
index bd57d6e3..f5f751ec 100644
--- a/composer.json
+++ b/composer.json
@@ -90,7 +90,7 @@
},
"extra": {
"branch-alias": {
- "dev-develop": "0.17-dev"
+ "dev-develop": "0.18-dev"
}
}
}
diff --git a/docs/conf.py b/docs/conf.py
index d83c43f5..fdfe14ca 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,7 +48,7 @@ copyright = u'2014-2017, PHPWord Contributors'
# built documents.
#
# The short X.Y version.
-version = '0.16.0'
+version = '0.17.0'
# The full version, including alpha/beta/rc tags.
release = version
diff --git a/docs/installing.rst b/docs/installing.rst
index 34353be8..2a9582d0 100644
--- a/docs/installing.rst
+++ b/docs/installing.rst
@@ -34,7 +34,7 @@ Example:
{
"require": {
- "phpoffice/phpword": "v0.14.*"
+ "phpoffice/phpword": "v0.17.*"
}
}