diff --git a/composer.json b/composer.json index f5f751ec04..276d4e0806 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ "require": { "php": "^5.3.3 || ^7.0", "ext-xml": "*", - "zendframework/zend-escaper": "^2.2", + "laminas/laminas-escaper": "^2.6", "phpoffice/common": "^0.2.9" }, "require-dev": { diff --git a/docs/elements.rst b/docs/elements.rst index 9d446b27d0..e497491533 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -359,17 +359,17 @@ The footnote numbering can be controlled by setting the FootnoteProperties on th .. code-block:: php - $fp = new PhpWord\SimpleType\FootnoteProperties(); + $fp = new \PhpOffice\PhpWord\ComplexType\FootnoteProperties(); //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) - $fp->setPos(FootnoteProperties::POSITION_DOC_END); + $fp->setPos(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::POSITION_BENEATH_TEXT); //set the number format to use (decimal (default), upperRoman, upperLetter, ...) - $fp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $fp->setNumFmt(\PhpOffice\PhpWord\SimpleType\NumberFormat::LOWER_ROMAN); //force starting at other than 1 $fp->setNumStart(2); //when to restart counting (continuous (default), eachSect, eachPage) - $fp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); + $fp->setNumRestart(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::RESTART_NUMBER_EACH_PAGE); //And finaly, set it on the Section - $section->setFootnoteProperties($properties); + $section->setFootnoteProperties($fp); Checkboxes ---------- diff --git a/docs/styles.rst b/docs/styles.rst index 27f8ee66ce..18a9c2eca3 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -75,8 +75,10 @@ Available Paragraph style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. - ``basedOn``. Parent style. -- ``hanging``. Hanging in *twip*. -- ``indent``. Indent in *twip*. +- ``hanging``. Hanging indentation in *half inches*. +- ``indent``. Indent (left indentation) in *half inches*. +- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine* and *hanging* indentation. + See ``\PhpOffice\PhpWord\Style\Indentation`` for possible identation types. - ``keepLines``. Keep all lines on one page, *true* or *false*. - ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. - ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc. diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index c4c3db4e12..5bc114549d 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -244,3 +244,20 @@ See ``Sample_40_TemplateSetComplexValue.php`` for examples. $table->addCell(150)->addText('Cell B2'); $table->addCell(150)->addText('Cell B3'); $templateProcessor->setComplexBlock('table', $table); + +save +""""""""" +Saves the loaded template within the current directory. Returns the file path. + +.. code-block:: php + + $filepath = $templateProcessor->save(); + +saveAs +""""""""" +Saves a copy of the loaded template in the indicated path. + +.. code-block:: php + + $pathToSave = 'path/to/save/file.ext'; + $templateProcessor->saveAs($pathToSave); diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index b495ef7bca..b6da9f3b9d 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -146,6 +146,18 @@ public function getFooters() * * @return FootnoteProperties */ + public function getFootnoteProperties() + { + return $this->footnoteProperties; + } + + /** + * Get the footnote properties + * + * @deprecated Use the `getFootnoteProperties` method instead + * + * @return FootnoteProperties + */ public function getFootnotePropoperties() { return $this->footnoteProperties; diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index b8e0b2169c..42eb22a777 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -26,8 +26,14 @@ class Rtf extends AbstractEscaper { protected function escapeAsciiCharacter($code) { - if (20 > $code || $code >= 80) { - return '{\u' . $code . '}'; + if ($code == 9) { + return '{\\tab}'; + } + if (0x20 > $code || $code >= 0x80) { + return '{\\u' . $code . '}'; + } + if ($code == 123 || $code == 125 || $code == 92) { // open or close brace or backslash + return '\\' . chr($code); } return chr($code); @@ -35,7 +41,7 @@ protected function escapeAsciiCharacter($code) protected function escapeMultibyteCharacter($code) { - return '\uc0{\u' . $code . '}'; + return '\\uc0{\\u' . $code . '}'; } /** diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 6e9aaf15dc..72f0f8096c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -198,7 +198,7 @@ public function setStyleValue($key, $value) { $key = Text::removeUnderscorePrefix($key); if ('indent' == $key || 'hanging' == $key) { - $value = $value * 720; + $value = $value * 720; // 720 twips is 0.5 inch } return parent::setStyleValue($key, $value); diff --git a/src/PhpWord/Writer/HTML/Element/ListItemRun.php b/src/PhpWord/Writer/HTML/Element/ListItemRun.php new file mode 100644 index 0000000000..a4d7e46073 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/ListItemRun.php @@ -0,0 +1,43 @@ +element instanceof \PhpOffice\PhpWord\Element\ListItemRun) { + return ''; + } + + $writer = new Container($this->parentWriter, $this->element); + $content = $writer->write() . PHP_EOL; + + return $content; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 986b498570..e0cabd7e1c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -126,27 +126,27 @@ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) $xmlWriter->endElement(); } - //footnote properties - if ($section->getFootnotePropoperties() !== null) { + // Footnote properties + if ($section->getFootnoteProperties() !== null) { $xmlWriter->startElement('w:footnotePr'); - if ($section->getFootnotePropoperties()->getPos() != null) { + if ($section->getFootnoteProperties()->getPos() != null) { $xmlWriter->startElement('w:pos'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getPos()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getPos()); $xmlWriter->endElement(); } - if ($section->getFootnotePropoperties()->getNumFmt() != null) { + if ($section->getFootnoteProperties()->getNumFmt() != null) { $xmlWriter->startElement('w:numFmt'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumFmt()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumFmt()); $xmlWriter->endElement(); } - if ($section->getFootnotePropoperties()->getNumStart() != null) { + if ($section->getFootnoteProperties()->getNumStart() != null) { $xmlWriter->startElement('w:numStart'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumStart()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumStart()); $xmlWriter->endElement(); } - if ($section->getFootnotePropoperties()->getNumRestart() != null) { + if ($section->getFootnoteProperties()->getNumRestart() != null) { $xmlWriter->startElement('w:numRestart'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumRestart()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumRestart()); $xmlWriter->endElement(); } $xmlWriter->endElement(); diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php new file mode 100644 index 0000000000..21c8a8c34f --- /dev/null +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -0,0 +1,83 @@ +write()); + + return $txt2; + } + + public function expect($str) + { + return self::HEADER . $str . self::TRAILER; + } + + /** + * Test special characters which require escaping + */ + public function testSpecial() + { + $str = 'Special characters { open brace } close brace \\ backslash'; + $expect = $this->expect('Special characters \\{ open brace \\} close brace \\\\ backslash'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test accented character + */ + public function testAccent() + { + $str = 'Voilà - string with accented char'; + $expect = $this->expect('Voil\\uc0{\\u224} - string with accented char'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test Hebrew + */ + public function testHebrew() + { + $str = 'Hebrew - שלום'; + $expect = $this->expect('Hebrew - \\uc0{\\u1513}\\uc0{\\u1500}\\uc0{\\u1493}\\uc0{\\u1501}'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test tab + */ + public function testTab() + { + $str = "Here's a tab\tfollowed by more characters."; + $expect = $this->expect("Here's a tab{\\tab}followed by more characters."); + $this->assertEquals($expect, $this->escapestring($str)); + } +} diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 3cf62b59f4..cca413f505 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -34,6 +34,22 @@ public function testGetSectionMediaElementsWithNull() $this->assertEquals(array(), Media::getElements('section')); } + /** + * Get header media elements + */ + public function testGetHeaderMediaElementsWithNull() + { + $this->assertEquals(array(), Media::getElements('header')); + } + + /** + * Get footer media elements + */ + public function testGetFooterMediaElementsWithNull() + { + $this->assertEquals(array(), Media::getElements('footer')); + } + /** * Count section media elements */ diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index d818e0f8bb..4acd0fe67a 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -225,4 +225,13 @@ public function testSortSections() $this->assertEquals(2, $phpWord->getSection(0)->countElements()); $this->assertEquals(1, $phpWord->getSection(1)->countElements()); } + + /** + * @covers \PhpOffice\PhpWord\PhpWord::getSettings + */ + public function testGetSettings() + { + $phpWord = new PhpWord(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Metadata\\Settings', $phpWord->getSettings()); + } } diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index cbc39c871e..d45bb74962 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -33,6 +33,7 @@ class StyleTest extends \PHPUnit\Framework\TestCase * @covers ::addParagraphStyle * @covers ::addFontStyle * @covers ::addLinkStyle + * @covers ::addNumberingStyle * @covers ::addTitleStyle * @covers ::addTableStyle * @covers ::setDefaultParagraphStyle @@ -47,6 +48,20 @@ public function testStyles() $paragraph = array('alignment' => Jc::CENTER); $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); + $numbering = array( + 'type' => 'multilevel', + 'levels' => array( + array( + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'alignment' => Jc::START, + ), + ), + ); + $styles = array( 'Paragraph' => 'Paragraph', 'Font' => 'Font', @@ -54,12 +69,13 @@ public function testStyles() 'Table' => 'Table', 'Heading_1' => 'Font', 'Normal' => 'Paragraph', + 'Numbering' => 'Numbering', ); Style::addParagraphStyle('Paragraph', $paragraph); Style::addFontStyle('Font', $font); Style::addLinkStyle('Link', $font); - // @todo Style::addNumberingStyle + Style::addNumberingStyle('Numbering', $numbering); Style::addTitleStyle(1, $font); Style::addTableStyle('Table', $table); Style::setDefaultParagraphStyle($paragraph); diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 101e226f50..4eb92fe557 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -34,7 +34,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Footnote', 'Image', 'Link', 'ListItem', 'Table', 'Title', 'Bookmark'); + $elements = array('Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Table', 'Title', 'Bookmark'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Element\\' . $element; $parentWriter = new HTML(); @@ -163,6 +163,31 @@ public function testWriteTitleTextRun() $this->assertContains($expected, $content); } + /** + * Test write element ListItemRun + */ + public function testListItemRun() + { + $expected1 = 'List item run 1'; + $expected2 = 'List item run 1 in bold'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle'); + $listItemRun->addText($expected1); + $listItemRun->addText($expected2, array('bold' => true)); + + $htmlWriter = new HTML($phpWord); + $content = $htmlWriter->getContent(); + + $dom = new \DOMDocument(); + $dom->loadHTML($content); + + $this->assertEquals($expected1, $dom->getElementsByTagName('p')->item(0)->textContent); + $this->assertEquals($expected2, $dom->getElementsByTagName('p')->item(1)->textContent); + } + /** * Tests writing table with layout */ diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 4b01bacfa2..3e9c235d13 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -24,6 +24,11 @@ */ class ElementTest extends \PHPUnit\Framework\TestCase { + public function removeCr($field) + { + return str_replace("\r\n", "\n", $field->write()); + } + /** * Test unmatched elements */ @@ -46,7 +51,7 @@ public function testPageField() $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()); + $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testNumpageField() @@ -55,7 +60,7 @@ public function testNumpageField() $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()); + $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testDateField() @@ -64,7 +69,7 @@ public function testDateField() $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()); + $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testIndexField() @@ -73,6 +78,6 @@ public function testIndexField() $element = new \PhpOffice\PhpWord\Element\Field('INDEX'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{}\\par\n", $field->write()); + $this->assertEquals("{}\\par\n", $this->removeCr($field)); } }