From e24b2e1ba78f828c79db5b8538c4cc4934c4b560 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 5 Jan 2020 10:27:45 -0800 Subject: [PATCH 01/58] ODT Changes Implement a number of features implemented in PhpWord, but not yet supported in PhpWord ODT Writer. 1. Add default file to tests/PhpWord/_includes/XmlDocument.php to make it considerably easier to test ODT changes (and Word2007 changes involving files other that document.xml). 2. Page break before each section. 3. Page numbering start. 4. Font style for Headings. 5. Alignment for images. 6. Paragraph style for TextRun. 7. "Hide grammatical errors" for whole document. 8. Page layout for each section. 9. For each page layout, support user-specified page width, page height, orientation, margin top, margin bottom, margin left, margin right. 10. Page header and footer. 11. Named colors. 12. NoProof font style. 13. Paragraph Style - spaceBefore, spaceAfter, lineHeight, pageBreakBefore, indentation, text alignment. 14. Tab stops. 15. Basic support for some Fields (DATE, PAGE, NUMPAGES). 16. Link had an error in how it was handling internal links (needs leading #). 17. In addition to tests for all the above, added some tests for Tables. Item 11 above needs 1 module from Pull Request 1775, which is targeted for v0.18.0 but not yet merged, so the relevant module is also here. Item 15 above needs 1 module from Pull Request 1774, which is targeted for v0.18.0 but not yet merged, so the relevant module is also here. Testing change from Pull Request 1771 is included here, but was merged after my fork. --- src/PhpWord/Element/Field.php | 40 +- src/PhpWord/Shared/Converter.php | 46 ++ src/PhpWord/Writer/ODText/Element/Field.php | 81 ++++ src/PhpWord/Writer/ODText/Element/Image.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- .../Writer/ODText/Element/PageBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 48 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 7 +- src/PhpWord/Writer/ODText/Element/Title.php | 19 +- src/PhpWord/Writer/ODText/Part/Content.php | 109 ++++- src/PhpWord/Writer/ODText/Part/Styles.php | 143 +++++- src/PhpWord/Writer/ODText/Style/Font.php | 19 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 113 ++++- .../Writer/ODText/Element/ImageTest.php | 66 +++ tests/PhpWord/Writer/ODText/ElementTest.php | 174 ++++++- .../Writer/ODText/Part/ContentTest.php | 2 +- .../PhpWord/Writer/ODText/Style/FontTest.php | 131 ++++++ .../Writer/ODText/Style/ParagraphTest.php | 434 ++++++++++++++++++ .../Writer/ODText/Style/SectionTest.php | 249 ++++++++++ tests/PhpWord/_includes/TestHelperDOCX.php | 7 +- tests/PhpWord/_includes/XmlDocument.php | 62 ++- 21 files changed, 1679 insertions(+), 77 deletions(-) create mode 100644 src/PhpWord/Writer/ODText/Element/Field.php create mode 100644 tests/PhpWord/Writer/ODText/Element/ImageTest.php create mode 100644 tests/PhpWord/Writer/ODText/Style/FontTest.php create mode 100644 tests/PhpWord/Writer/ODText/Style/ParagraphTest.php create mode 100644 tests/PhpWord/Writer/ODText/Style/SectionTest.php diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 2efc6b0b..3d1503fe 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Font; + /** * Field element * @@ -115,10 +117,42 @@ class Field extends AbstractElement /** * Font style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|\PhpOffice\PhpWord\Style\Font */ protected $fontStyle; + /** + * Set Font style + * + * @param string|array|\PhpOffice\PhpWord\Style\Font $style + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function setFontStyle($style = null) + { + if ($style instanceof Font) { + $this->fontStyle = $style; + } elseif (is_array($style)) { + $this->fontStyle = new Font('text'); + $this->fontStyle->setStyleByArray($style); + } elseif (null === $style) { + $this->fontStyle = null; + } else { + $this->fontStyle = $style; + } + + return $this->fontStyle; + } + + /** + * Get Font style + * + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function getFontStyle() + { + return $this->fontStyle; + } + /** * Create a new Field Element * @@ -126,13 +160,15 @@ class Field extends AbstractElement * @param array $properties * @param array $options * @param TextRun|string|null $text + * @param string|array|\PhpOffice\PhpWord\Style\Font $fontStyle */ - public function __construct($type = null, $properties = array(), $options = array(), $text = null) + public function __construct($type = null, $properties = array(), $options = array(), $text = null, $fontStyle = null) { $this->setType($type); $this->setProperties($properties); $this->setOptions($options); $this->setText($text); + $this->setFontStyle($fontStyle); } /** diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 7008ac5d..9206a3bc 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -272,6 +272,50 @@ class Converter return round($angle / self::DEGREE_TO_ANGLE); } + /** + * Convert colorname as string to RGB + * + * @param string $value color name + * @return string color as hex RGB string, or original value if unknown + */ + public static function stringToRgb($value) + { + switch ($value) { + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW: + return 'FFFF00'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGREEN: + return '90EE90'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_CYAN: + return '00FFFF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_MAGENTA: + return 'FF00FF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLUE: + return '0000FF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_RED: + return 'FF0000'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKBLUE: + return '00008B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKCYAN: + return '008B8B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN: + return '006400'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA: + return '8B008B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKRED: + return '8B0000'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKYELLOW: + return '8B8B00'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGRAY: + return 'A9A9A9'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGRAY: + return 'D3D3D3'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLACK: + return '000000'; + } + + return $value; + } + /** * Convert HTML hexadecimal to RGB * @@ -282,6 +326,8 @@ class Converter { if ($value[0] == '#') { $value = substr($value, 1); + } else { + $value = self::stringToRgb($value); } if (strlen($value) == 6) { diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php new file mode 100644 index 00000000..c95139ac --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -0,0 +1,81 @@ +getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + return; + } + + $type = strtolower($element->getType()); + switch ($type) { + case 'date': // Owen 2020-01-02 + case 'page': + case 'numpages': + $this->writeDefault($element, $type); + break; + } + } + + private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type) + { + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('text:span'); + if (method_exists($element, 'getFontStyle')) { + $fstyle = $element->getFontStyle(); + if (is_string($fstyle)) { + $xmlWriter->writeAttribute('text:style-name', $fstyle); + } + } + switch ($type) { + case 'date': // Owen 2019-01-02 + $xmlWriter->startElement('text:date'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $xmlWriter->endElement(); + break; + case 'page': + $xmlWriter->startElement('text:page-number'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $xmlWriter->endElement(); + break; + case 'numpages': + $xmlWriter->startElement('text:page-count'); + $xmlWriter->endElement(); + break; + } + $xmlWriter->endElement(); // text:span + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index add45e10..57aa546a 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -44,7 +44,7 @@ class Image extends AbstractElement $height = Converter::pixelToCm($style->getHeight()); $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'Standard'); + $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); $xmlWriter->startElement('draw:frame'); $xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex); diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index d6fec507..23c9804b 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -41,7 +41,7 @@ class Link extends AbstractElement $xmlWriter->startElement('text:a'); $xmlWriter->writeAttribute('xlink:type', 'simple'); - $xmlWriter->writeAttribute('xlink:href', $element->getSource()); + $xmlWriter->writeAttribute('xlink:href', ($element->isInternal() ? '#' : '') . $element->getSource()); $this->writeText($element->getText()); $xmlWriter->endElement(); // text:a diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index ecf47607..8e4f4695 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -30,7 +30,7 @@ class PageBreak extends AbstractElement $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'P1'); + $xmlWriter->writeAttribute('text:style-name', 'PB'); $xmlWriter->endElement(); } } diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 7dcd28a0..2bf9908d 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -59,18 +59,26 @@ class Text extends AbstractElement } else { if (empty($fontStyle)) { if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } } $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->writeText($element->getText()); + $this->replaceTabs($element->getText(), $xmlWriter); $this->writeChangeInsertion(false, $element->getTrackChange()); } else { if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } } // text:span $xmlWriter->startElement('text:span'); @@ -78,7 +86,7 @@ class Text extends AbstractElement $xmlWriter->writeAttribute('text:style-name', $fontStyle); } $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->writeText($element->getText()); + $this->replaceTabs($element->getText(), $xmlWriter); $this->writeChangeInsertion(false, $element->getTrackChange()); $xmlWriter->endElement(); } @@ -88,6 +96,34 @@ class Text extends AbstractElement } } + private function replacetabs($text, $xmlWriter) + { + if (preg_match('/^ +/', $text, $matches)) { + $num = strlen($matches[0]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + $text = preg_replace('/^ +/', '', $text); + } + preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $this->writeText($match[1]); + if ($match[2] === '') { + break; + } elseif ($match[2] === "\t") { + $xmlWriter->writeElement('text:tab'); + } elseif ($match[2] === ' ') { + $xmlWriter->writeElement('text:s'); + break; + } else { + $num = strlen($match[2]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + } + } + } + private function writeChangeInsertion($start = true, TrackChange $trackChange = null) { if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) { diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 78e5a8ad..cde996f6 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -22,7 +22,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; * * @since 0.10.0 */ -class TextRun extends AbstractElement +class TextRun extends Text { /** * Write element @@ -33,6 +33,11 @@ class TextRun extends AbstractElement $element = $this->getElement(); $xmlWriter->startElement('text:p'); + $pStyle = $element->getParagraphStyle(); + if (!is_string($pStyle)) { + $pStyle = 'Normal'; + } + $xmlWriter->writeAttribute('text:style-name', $pStyle); $containerWriter = new Container($xmlWriter, $element); $containerWriter->write(); diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 8b9440ab..99153b5e 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -36,7 +36,23 @@ class Title extends AbstractElement } $xmlWriter->startElement('text:h'); - $xmlWriter->writeAttribute('text:outline-level', $element->getDepth()); + $hdname = 'HD'; + $sect = $element->getParent(); + if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { + $elems = $sect->getElements(); + if ($elems[0] === $element) { + $hdname = 'HE'; + } + } + $depth = $element->getDepth(); + $xmlWriter->writeAttribute('text:style-name', "$hdname$depth"); + $xmlWriter->writeAttribute('text:outline-level', $depth); + $xmlWriter->startElement('text:span'); + if ($depth > 0) { + $xmlWriter->writeAttribute('text:style-name', 'Heading_' . $depth); + } else { + $xmlWriter->writeAttribute('text:style-name', 'Title'); + } $text = $element->getText(); if (is_string($text)) { $this->writeText($text); @@ -44,6 +60,7 @@ class Title extends AbstractElement $containerWriter = new Container($xmlWriter, $text); $containerWriter->write(); } + $xmlWriter->endElement(); // text:span $xmlWriter->endElement(); // text:h } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 99ee9353..8eaad40f 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -46,6 +46,7 @@ class Content extends AbstractPart * @var array */ private $autoStyles = array('Section' => array(), 'Image' => array(), 'Table' => array()); + private $imageParagraphStyles = array(); /** * Write part @@ -128,6 +129,9 @@ class Content extends AbstractPart $xmlWriter->startElement('text:section'); $xmlWriter->writeAttribute('text:name', $name); $xmlWriter->writeAttribute('text:style-name', $name); + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'SB' . $section->getSectionId()); + $xmlWriter->endElement(); $containerWriter = new Container($xmlWriter, $section); $containerWriter->write(); $xmlWriter->endElement(); // text:section @@ -174,28 +178,58 @@ class Content extends AbstractPart { $styles = Style::getStyles(); $paragraphStyleCount = 0; - if (count($styles) > 0) { - foreach ($styles as $style) { - if ($style->isAuto() === true) { - $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); - if (class_exists($styleClass)) { - /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ - $styleWriter = new $styleClass($xmlWriter, $style); - $styleWriter->write(); - } - if ($style instanceof Paragraph) { - $paragraphStyleCount++; - } - } - } - if ($paragraphStyleCount == 0) { + + $style = new Paragraph(); + $style->setStyleName('PB'); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $sects = $this->getParentWriter()->getPhpWord()->getSections(); + for ($i = 0; $i < count($sects); ++$i) { + $iplus1 = $i + 1; + $style = new Paragraph(); + $style->setStyleName("SB$iplus1"); + $style->setAuto(); + $pnstart = $sects[$i]->getStyle()->getPageNumberingStart(); + $style->setNumLevel($pnstart); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + } + + foreach ($styles as $style) { + $sty = $style->getStyleName(); + if (substr($sty, 0, 8) === 'Heading_') { $style = new Paragraph(); - $style->setStyleName('P1'); + $style->setStyleName('HD' . substr($sty, 8)); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + $style = new Paragraph(); + $style->setStyleName('HE' . substr($sty, 8)); $style->setAuto(); $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); $styleWriter->write(); } } + + foreach ($styles as $style) { + if ($style->isAuto() === true) { + $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); + if (class_exists($styleClass)) { + /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ + $styleWriter = new $styleClass($xmlWriter, $style); + $styleWriter->write(); + } + if ($style instanceof Paragraph) { + $paragraphStyleCount++; + } + } + } + foreach ($this->imageParagraphStyles as $style) { + $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); + $styleWriter->write(); + } } /** @@ -231,6 +265,7 @@ class Content extends AbstractPart $elements = $container->getElements(); foreach ($elements as $element) { if ($element instanceof TextRun) { + $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); @@ -238,13 +273,19 @@ class Content extends AbstractPart $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); $this->autoStyles['Image'][] = $style; + $sty = new \PhpOffice\PhpWord\Style\Paragraph(); + $sty->setStyleName('IM' . $element->getMediaIndex()); + $sty->setAuto(); + $sty->setAlignment($style->getAlignment()); + $this->imageParagraphStyles[] = $sty; } elseif ($element instanceof Table) { /** @var \PhpOffice\PhpWord\Style\Table $style */ $style = $element->getStyle(); + if (is_string($style)) { + $style = Style::getStyle($style); + } if ($style === null) { $style = new TableStyle(); - } elseif (is_string($style)) { - $style = Style::getStyle($style); } $style->setStyleName($element->getElementId()); $style->setColumnWidths($element->findFirstDefinedCellWidths()); @@ -268,16 +309,34 @@ class Content extends AbstractPart if ($fontStyle instanceof Font) { // Font - $fontStyleCount++; - $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle); - $style->setAuto(); - $element->setFontStyle("T{$fontStyleCount}"); - } elseif ($paragraphStyle instanceof Paragraph) { + $name = $fontStyle->getStyleName(); + if (!$name) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle, null); + $style->setAuto(); + $style->setParagraph(null); + $element->setFontStyle("T{$fontStyleCount}"); + } else { + $element->setFontStyle($name); + } + } + if ($paragraphStyle instanceof Paragraph) { // Paragraph + $name = $paragraphStyle->getStyleName(); + if (!$name) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } else { + $element->setParagraphStyle($name); + } + } elseif (is_string($paragraphStyle)) { $paragraphStyleCount++; - $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array()); + $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; + $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); $style->setAuto(); - $element->setParagraphStyle("P{$paragraphStyleCount}"); + $element->setParagraphStyle($parstylename); } } diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index e7635e98..862f4b2a 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; /** @@ -86,6 +87,9 @@ class Styles extends AbstractPart $latinLang = $language != null && is_string($language->getLatin()) ? explode('-', $language->getLatin()) : array('fr', 'FR'); $asianLang = $language != null && is_string($language->getEastAsia()) ? explode('-', $language->getEastAsia()) : array('zh', 'CN'); $complexLang = $language != null && is_string($language->getBidirectional()) ? explode('-', $language->getBidirectional()) : array('hi', 'IN'); + if ($this->getParentWriter()->getPhpWord()->getSettings()->hasHideGrammaticalErrors()) { + $latinLang = $asianLang = $complexLang = array('zxx', 'none'); + } // Font $xmlWriter->startElement('style:text-properties'); @@ -134,24 +138,87 @@ class Styles extends AbstractPart } /** - * Write page layout styles. + * Convert int in twips to inches/cm then to string and append unit + * + * @param int $twips + * @param string $dflt + * @param float $factor + * return string + */ + private static function cvttwiptostr($twips, $dflt, $factor = 1.0) // Owen 2019-08-06 + { + if ($twips === null) { + return $dflt; + } + $ins = (string) ($twips * $factor / Converter::INCH_TO_TWIP) . 'in'; + $cms = (string) ($twips * $factor * Converter::INCH_TO_CM / Converter::INCH_TO_TWIP) . 'cm'; + + return (strlen($ins) < strlen($cms)) ? $ins : $cms; + } + + /** + * call writePageLayoutIndiv to write page layout styles for each page * * @param \PhpOffice\Common\XMLWriter $xmlWriter */ - private function writePageLayout(XMLWriter $xmlWriter) + private function writePageLayout(XMLWriter $xmlWriter) // Owen 2019-06-19 { + $sections = $this->getParentWriter()->getPhpWord()->getSections(); + for ($i = 0; $i < count($sections); ++$i) { + $this->writePageLayoutIndiv($xmlWriter, $sections[$i], $i + 1); + } + } + + /** + * Write page layout styles. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section + * @param int $sectionNbr + */ + private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNbr) + { + $sty = $section->getStyle(); + if (count($section->getHeaders()) > 0) { + $topfactor = 0.5; + } else { + $topfactor = 1.0; + } + if (count($section->getFooters()) > 0) { + $botfactor = 0.5; + } else { + $botfactor = 1.0; + } + $pwidth = '21.001cm'; + $pheight = '29.7cm'; + $orient = 'portrait'; + $mtop = $mleft = $mright = '2.501cm'; + $mbottom = '2cm'; + if ($sty instanceof \PhpOffice\PhpWord\Style\Section) { + $ori = $sty->getOrientation(); + if ($ori !== null) { + $orient = $ori; + } + $pwidth = self::cvttwiptostr($sty->getPageSizeW(), $pwidth); + $pheight = self::cvttwiptostr($sty->getPageSizeH(), $pheight); + $mtop = self::cvttwiptostr($sty->getMarginTop(), $mtop, $topfactor); + $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $mbottom, $botfactor); + $mleft = self::cvttwiptostr($sty->getMarginRight(), $mleft); + $mright = self::cvttwiptostr($sty->getMarginLeft(), $mright); + } + $xmlWriter->startElement('style:page-layout'); - $xmlWriter->writeAttribute('style:name', 'Mpm1'); + $xmlWriter->writeAttribute('style:name', "Mpm$sectionNbr"); $xmlWriter->startElement('style:page-layout-properties'); - $xmlWriter->writeAttribute('fo:page-width', '21.001cm'); - $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); + $xmlWriter->writeAttribute('fo:page-width', $pwidth); + $xmlWriter->writeAttribute('fo:page-height', $pheight); $xmlWriter->writeAttribute('style:num-format', '1'); - $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); - $xmlWriter->writeAttribute('fo:margin-top', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', '2cm'); - $xmlWriter->writeAttribute('fo:margin-left', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-right', '2.501cm'); + $xmlWriter->writeAttribute('style:print-orientation', $orient); + $xmlWriter->writeAttribute('fo:margin-top', $mtop); + $xmlWriter->writeAttribute('fo:margin-bottom', $mbottom); + $xmlWriter->writeAttribute('fo:margin-left', $mleft); + $xmlWriter->writeAttribute('fo:margin-right', $mright); $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb'); $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0'); $xmlWriter->writeAttribute('style:layout-grid-lines', '25199'); @@ -176,9 +243,23 @@ class Styles extends AbstractPart $xmlWriter->endElement(); // style:page-layout-properties $xmlWriter->startElement('style:header-style'); + if ($topfactor < 1.0) { + $xmlWriter->startElement('style:header-footer-properties'); + $xmlWriter->writeAttribute('fo:min-height', $mtop); + $xmlWriter->writeAttribute('fo:margin-bottom', $mtop); + $xmlWriter->writeAttribute('style:dynamic-spacing', 'true'); + $xmlWriter->endElement(); // style:header-footer-properties + } $xmlWriter->endElement(); // style:header-style $xmlWriter->startElement('style:footer-style'); + if ($botfactor < 1.0) { // Owen 2019-08-03 + $xmlWriter->startElement('style:header-footer-properties'); + $xmlWriter->writeAttribute('fo:min-height', $mbottom); + $xmlWriter->writeAttribute('fo:margin-top', $mbottom); + $xmlWriter->writeAttribute('style:dynamic-spacing', 'true'); + $xmlWriter->endElement(); // style:header-footer-properties + } $xmlWriter->endElement(); // style:footer-style $xmlWriter->endElement(); // style:page-layout @@ -193,11 +274,43 @@ class Styles extends AbstractPart { $xmlWriter->startElement('office:master-styles'); - $xmlWriter->startElement('style:master-page'); - $xmlWriter->writeAttribute('style:name', 'Standard'); - $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); - $xmlWriter->endElement(); // style:master-page - + $sections = $this->getParentWriter()->getPhpWord()->getSections(); + for ($i = 0; $i < count($sections); ++$i) { + $iplus1 = $i + 1; + $xmlWriter->startElement('style:master-page'); + $xmlWriter->writeAttribute('style:name', "Standard$iplus1"); + $xmlWriter->writeAttribute('style:page-layout-name', "Mpm$iplus1"); + // Multiple headers and footers probably not supported, + // and, even if they are, I'm not sure how, + // so quit after generating one. + foreach ($sections[$i]->getHeaders() as $hdr) { + $xmlWriter->startElement('style:header'); + foreach ($hdr->getElements() as $elem) { + $cl1 = get_class($elem); + $cl2 = str_replace('\\Element\\', '\\Writer\\ODText\\Element\\', $cl1); + if (class_exists($cl2)) { + $wtr = new $cl2($xmlWriter, $elem); + $wtr->write(); + } + } + $xmlWriter->endElement(); // style:header + break; + } + foreach ($sections[$i]->getFooters() as $hdr) { + $xmlWriter->startElement('style:footer'); + foreach ($hdr->getElements() as $elem) { + $cl1 = get_class($elem); + $cl2 = str_replace('\\Element\\', '\\Writer\\ODText\\Element\\', $cl1); + if (class_exists($cl2)) { + $wtr = new $cl2($xmlWriter, $elem); + $wtr->write(); + } + } + $xmlWriter->endElement(); // style:footer + break; + } + $xmlWriter->endElement(); // style:master-page + } $xmlWriter->endElement(); // office:master-styles } } diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 29657c5a..ae9c417e 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -35,6 +35,14 @@ class Font extends AbstractStyle } $xmlWriter = $this->getXmlWriter(); + $stylep = (method_exists($style, 'getParagraph')) ? $style->getParagraph() : null; + if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + $temp1 = clone $stylep; + $temp1->setStyleName($style->getStyleName()); + $temp2 = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $temp1); + $temp2->write(); + } + $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'text'); @@ -53,7 +61,7 @@ class Font extends AbstractStyle // Color $color = $style->getColor(); - $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . $color); + $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . \PhpOffice\PhpWord\Shared\Converter::stringToRgb($color)); // Bold & italic $xmlWriter->writeAttributeIf($style->isBold(), 'fo:font-weight', 'bold'); @@ -82,6 +90,15 @@ class Font extends AbstractStyle $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super'); $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub'); + if ($style->isNoProof()) { + $xmlWriter->writeAttribute('fo:language', 'zxx'); + $xmlWriter->writeAttribute('style:language-asian', 'zxx'); + $xmlWriter->writeAttribute('style:language-complex', 'zxx'); + $xmlWriter->writeAttribute('fo:country', 'none'); + $xmlWriter->writeAttribute('style:country-asian', 'none'); + $xmlWriter->writeAttribute('style:country-complex', 'none'); + } + // @todo Foreground-Color // @todo Background color diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index f247dcc1..555a4825 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Shared\Converter; + /** * Font style writer * @@ -35,31 +37,120 @@ class Paragraph extends AbstractStyle } $xmlWriter = $this->getXmlWriter(); - $marginTop = (is_null($style->getSpaceBefore()) || $style->getSpaceBefore() == 0) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); - $marginBottom = (is_null($style->getSpaceAfter()) || $style->getSpaceAfter() == 0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); + $marginTop = $style->getSpaceBefore(); + $marginBottom = $style->getSpaceAfter(); $xmlWriter->startElement('style:style'); + + $styleName = $style->getStyleName(); + $styleAuto = false; + $mpm = ''; + $psm = ''; + $pagestart = -1; + $breakafter = $breakbefore = $breakauto = false; + if ($style->isAuto()) { + if (substr($styleName, 0, 2) === 'PB') { + $styleAuto = true; + $breakafter = true; + } elseif (substr($styleName, 0, 2) === 'SB') { + $styleAuto = true; + $mpm = 'Standard' . substr($styleName, 2); + $psn = $style->getNumLevel(); + if (is_numeric($psn)) { + $pagestart = (int) $psn; + } + } elseif (substr($styleName, 0, 2) === 'HD') { + $styleAuto = true; + $psm = 'Heading_' . substr($styleName, 2); + $stylep = \PhpOffice\PhpWord\Style::getStyle($psm); + if ($stylep instanceof \PhpOffice\PhpWord\Style\Font) { + if (method_exists($stylep, 'getParagraph')) { + $stylep = $stylep->getParagraph(); + } + } + if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if ($stylep->hasPageBreakBefore()) { + $breakbefore = true; + } + } + } elseif (substr($styleName, 0, 2) === 'HE') { + $styleAuto = true; + $psm = 'Heading_' . substr($styleName, 2); + $breakauto = true; + } else { + $styleAuto = true; + $psm = 'Normal'; + if (preg_match('/^P\\d+_(\\w+)$/', $styleName, $matches)) { + $psm = $matches[1]; + } + } + } + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'paragraph'); - if ($style->isAuto()) { - $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); - $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); + if ($styleAuto) { + $xmlWriter->writeAttributeIf($psm !== '', 'style:parent-style-name', $psm); + $xmlWriter->writeAttributeIf($mpm !== '', 'style:master-page-name', $mpm); } $xmlWriter->startElement('style:paragraph-properties'); - if ($style->isAuto()) { - $xmlWriter->writeAttribute('style:page-number', 'auto'); - } else { - $xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm'); - $xmlWriter->writeAttribute('fo:text-align', $style->getAlignment()); + if ($styleAuto) { + if ($breakafter) { + $xmlWriter->writeAttribute('fo:break-after', 'page'); + $xmlWriter->writeAttribute('fo:margin-top', '0cm'); + $xmlWriter->writeAttribute('fo:margin-bottom', '0cm'); + } elseif ($breakbefore) { + $xmlWriter->writeAttribute('fo:break-before', 'page'); + } elseif ($breakauto) { + $xmlWriter->writeAttribute('fo:break-before', 'auto'); + } + if ($pagestart > 0) { + $xmlWriter->writeAttribute('style:page-number', $pagestart); + } + } + if (!$breakafter && !$breakbefore && !$breakauto) { + $twipToPoint = Converter::INCH_TO_TWIP / Converter::INCH_TO_POINT; // 20 + $xmlWriter->writeAttributeIf($marginTop !== null, 'fo:margin-top', ($marginTop / $twipToPoint) . 'pt'); + $xmlWriter->writeAttributeIf($marginBottom !== null, 'fo:margin-bottom', ($marginBottom / $twipToPoint) . 'pt'); + } + $temp = $style->getAlignment(); + $xmlWriter->writeAttributeIf($temp !== '', 'fo:text-align', $temp); + $temp = $style->getLineHeight(); + $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%')); + $xmlWriter->writeAttributeIf($style->getPageBreakBefore() === true, 'fo:break-before', 'page'); + + $tabs = $style->getTabs(); + if ($tabs !== null && count($tabs) > 0) { + $xmlWriter->startElement('style:tab-stops'); + foreach ($tabs as $tab) { + $xmlWriter->startElement('style:tab-stop'); + $xmlWriter->writeAttribute('style:type', $tab->getType()); + $xmlWriter->writeAttribute('style:position', (string) ($tab->getPosition() / Converter::INCH_TO_TWIP) . 'in'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); } //Right to left $xmlWriter->writeAttributeIf($style->isBidi(), 'style:writing-mode', 'rl-tb'); + //Indentation + $indent = $style->getIndentation(); + if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + $marg = $indent->getLeft(); + $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-left', (string) ($marg / Converter::INCH_TO_TWIP) . 'in'); + $marg = $indent->getRight(); + $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-right', (string) ($marg / Converter::INCH_TO_TWIP) . 'in'); + } + $xmlWriter->endElement(); //style:paragraph-properties + if ($styleAuto && substr($styleName, 0, 2) === 'SB') { + $xmlWriter->startElement('style:text-properties'); + $xmlWriter->writeAttribute('text:display', 'none'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); //style:style } } diff --git a/tests/PhpWord/Writer/ODText/Element/ImageTest.php b/tests/PhpWord/Writer/ODText/Element/ImageTest.php new file mode 100644 index 00000000..bc861104 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Element/ImageTest.php @@ -0,0 +1,66 @@ +addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); + $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', array('align' => 'end')); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('IM1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[4]"; + $this->assertEquals('IM2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); + $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 37f0d1ef..500ee247 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -26,6 +26,14 @@ use PhpOffice\PhpWord\TestHelperDOCX; */ class ElementTest extends \PHPUnit\Framework\TestCase { + /** + * Executed after each method of the class + */ + public function tearDown() + { + TestHelperDOCX::clear(); + } + /** * Test unmatched elements */ @@ -39,10 +47,168 @@ class ElementTest extends \PHPUnit\Framework\TestCase $object = new $objectClass($xmlWriter, $newElement); $object->write(); - $this->assertEquals('', $xmlWriter->getData()); + self::assertEquals('', $xmlWriter->getData()); } } + // ODT Line Element not yet implemented + // ODT Bookmark not yet implemented + // ODT Table with style name not yet implemented (Word test defective) + // ODT Shape Elements not yet implemented + // ODT Chart Elements not yet implemented + // ODT adding Field to Section not yet implemented + // ODT List not yet implemented + // ODT Macro Button not yet implemented + // ODT Form Field not yet implemented + // ODT SDT not yet implemented + // ODT Comment not yet implemented + // ODT Track Changes implemented, possibly not correctly + // ODT List Item not yet implemented + + /** + * Test link element + */ + public function testLinkElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $extlink = 'https://github.com/PHPOffice/PHPWord'; + $section->addLink($extlink); + $intlink = 'internal_link'; + $section->addLink($intlink, null, null, null, true); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]/text:a"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals($extlink, $doc->getElementAttribute($element, 'xlink:href')); + + $element = "$p2t/text:p[3]/text:a"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals("#$intlink", $doc->getElementAttribute($element, 'xlink:href')); + } + + /** + * Basic test for table element + */ + public function testTableElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); + $table->addRow(900); + $table->addCell(2000)->addText('Row 1'); + $table->addCell(2000)->addText('Row 2'); + $table->addCell(2000)->addText('Row 3'); + $table->addCell(2000)->addText('Row 4'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2s = '/office:document-content/office:automatic-styles'; + $tableStyleNum = 1; + $tableStyleName = ''; + while ($tableStyleName === '') { + $element = "$p2s/style:style[$tableStyleNum]"; + if (!$doc->elementExists($element)) { + break; + } + if ($doc->getElementAttribute($element, 'style:family') === 'table') { + $tableStyleName = $doc->getElementAttribute($element, 'style:name'); + break; + } + ++$tableStyleNum; + } + self::AssertNotEquals('', $tableStyleName); + $element = "$element/style:table-properties"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(\PhpOffice\PhpWord\SimpleType\JcTable::CENTER, $doc->getElementAttribute($element, 'table:align')); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $tableRootElement = "$p2t/table:table"; + self::assertTrue($doc->elementExists($tableRootElement)); + self::assertEquals($tableStyleName, $doc->getElementAttribute($tableRootElement, 'table:style')); + self::assertTrue($doc->elementExists($tableRootElement . '/table:table-column[4]')); + } + + /** + * Test Title and Headings + */ + public function testTitleAndHeading() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(0, array('size' => 14, 'italic' => true)); + $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); + + $section = $phpWord->addSection(); + $section->addTitle('This is a title', 0); + $section->addTitle('Heading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:h[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE0', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('0', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals('This is a title', $doc->getElement($span)->textContent); + $this->assertEquals('Title', $doc->getElementAttribute($span, 'text:style-name')); + + $element = "$p2t/text:h[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals('Heading 1', $doc->getElement($span)->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Title', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('14pt', $doc->getElementAttribute($element, 'fo:font-size')); + $this->assertEquals('italic', $doc->getElementAttribute($element, 'fo:font-style')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:font-weight')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:color')); + + $element = '/office:document-styles/office:styles/style:style[2]'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('20pt', $doc->getElementAttribute($element, 'fo:font-size')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:font-style')); + $this->assertEquals('bold', $doc->getElementAttribute($element, 'fo:font-weight')); + $this->assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color')); + } + + /** + * Test correct writing of text with ampersand in it + */ + public function testTextWithAmpersand() + { + $esc = \PhpOffice\PhpWord\Settings::isOutputEscapingEnabled(); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $txt = 'this text contains an & (ampersand)'; + $section->addText($txt); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled($esc); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]"; + $this->assertTrue($doc->elementExists($element)); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($txt, $doc->getElement($span)->nodeValue); + } + /** * Test PageBreak */ @@ -55,8 +221,8 @@ class ElementTest extends \PHPUnit\Framework\TestCase $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; - $this->assertTrue($doc->elementExists($element, 'content.xml')); - $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); + $element = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + self::assertTrue($doc->elementExists($element, 'content.xml')); + self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); } } diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 2e501c60..34eb8068 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -92,7 +92,7 @@ class ContentTest extends \PHPUnit\Framework\TestCase $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = '/office:document-content/office:body/office:text/text:section/text:p'; + $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); } diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php new file mode 100644 index 00000000..5306c6b0 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -0,0 +1,131 @@ +addSection(); + $section->addText('This is red (800) in rtf/html, default in docx/odt', array('color' => '800')); + $section->addText('This should be cyanish (008787)', array('color' => '008787')); + $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', array('color' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN)); + $section->addText('This color is default (unknow)', array('color' => 'unknow')); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('#008787', $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[3]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('This should be cyanish (008787)', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('#006400', $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue); + } + + /** + * Test noproof + */ + public function testNoProof() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Noproof not specified', array('color' => 'black')); + $section->addText('Noproof is true', array('color' => 'black', 'noproof' => true)); + $section->addText('Noproof is false', array('color' => 'black', 'noproof' => false)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:language')); + $span = "$s2t/text:p[2]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof not specified', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'fo:country')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex')); + $span = "$s2t/text:p[3]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof is true', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:language')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof is false', $doc->getElement($span)->nodeValue); + } +} diff --git a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php new file mode 100644 index 00000000..0e9948cf --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php @@ -0,0 +1,434 @@ +addSection(); + $section->addText('Text on first page'); + $section->addPageBreak(); + $section->addText('Text on second page'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[1]"; + $this->assertEquals('PB', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-after')); + $this->assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[3]"; + $this->assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test normal/indent + */ + public function testNormalIndent() + { + $phpWord = new PhpWord(); + $cvt = Converter::INCH_TO_TWIP; + $indent1 = array('indentation' => array('left' => 0.50 * $cvt)); + $indent2 = array('indentation' => array('left' => 1.00 * $cvt, 'right' => 1.05 * $cvt)); + $indent3 = array('indentation' => array('left' => -0.50 * $cvt)); + $indent4 = array('indentation' => array('left' => 0 * $cvt)); + $phpWord->setDefaultParagraphStyle($indent1); + $section = $phpWord->addSection(); + $section->addText('Should use default indent (0.5)'); + $section->addText('Should use non-default indent (1.0) on both sides, and here\'s an extra long line to prove it', null, $indent2); + $section->addText('Should use non-default indent (-0.5)', null, $indent3); + $section->addText('Should use non-default indent (0)', null, $indent4); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('1in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('1.05in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('-0.5in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[10]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + } + + /** + * Test textAlign + */ + public function testTextAlign() + { + $phpWord = new PhpWord(); + $align1 = array('alignment' => 'end'); + $align2 = array('alignment' => 'start'); + $phpWord->setDefaultParagraphStyle($align1); + $section = $phpWord->addSection(); + $section->addText('Should use default alignment (right for this doc)'); + $section->addText('Explicit left alignment', null, $align2); + $section->addText('Explicit right alignment', null, $align1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test lineHeight + */ + public function testLineHeight() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Should use line height 1.08, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 1.08)); + $section->addText('Should use line height 1.20, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 1.20)); + $section->addText('Should use line height 0.90, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 0.90)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('108%', $doc->getElementAttribute($element, 'fo:line-height')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('120%', $doc->getElementAttribute($element, 'fo:line-height')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('90%', $doc->getElementAttribute($element, 'fo:line-height')); + } + + /** + * Test SpaceBeforeAfter + */ + public function testSpaceBeforeAfter() + { + $phpWord = new PhpWord(); + $phpWord->setDefaultParagraphStyle(array('spaceBefore' => 0, 'spaceAfter' => 0)); + $section = $phpWord->addSection(); + $section->addText('No spacing between this paragraph and next'); + $section->addText('No spacing between this paragraph and previous'); + $section->addText('No spacing before this but 100 after', null, array('spaceAfter' => 100)); + $section->addText('No spacing for this paragraph but previous specified 100 after and next specifies 100 before'); + $section->addText('No spacing after this but 100 before', null, array('spaceBefore' => 100)); + $section->addText('No spacing before this paragraph'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $element = "$s2a/style:style[12]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-bottom')); + } + + /** + * Test Page Break Before + */ + public function testPageBreakBefore() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This is my first paragraph.'); + $section->addText('This is my second paragraph, on a new page.', null, array('pageBreakBefore' => true)); + $section->addText('This is my third paragraph, on same page as second.'); + $section->addText('This is my fourth paragraph, on a new page.', null, array('pageBreakBefore' => true)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[10]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + } + + /** + * Test Heading Page Break Before + */ + public function testHeadingPageBreakBefore() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, null, array('pageBreakBefore' => true)); + $phpWord->addTitleStyle(2, null, array()); + $section = $phpWord->addSection(); + $section->addTitle('Section1 Heading1 #1', 1); + $section->addTitle('Section1 Heading2 #1', 2); + $section->addTitle('Section1 Heading1 #2', 1); + $section->addTitle('Section1 Heading2 #2', 2); + $section = $phpWord->addSection(); + $section->addTitle('Section2 Heading1 #1', 1); + $section->addTitle('Section2 Heading2 #1', 2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[6]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before')); + + $s2a = '/office:document-content/office:body/office:text/text:section[1]'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[2]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[3]"; + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[4]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section[2]'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[2]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:styles'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/style:style[1]"; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[3]"; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + } + + /** + * Test text run paragraph style using named style + */ + public function testTextRun() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addParagraphStyle('parstyle1', array('align' => 'start')); + $phpWord->addParagraphStyle('parstyle2', array('align' => 'end')); + $section = $phpWord->addSection(); + $trx = $section->addTextRun('parstyle1'); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, 'parstyle2'); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, 'parstyle2'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element = "$s2a/style:style[9]"; + $this->assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:parent-style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + $this->assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + $this->assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + $element = '/office:document-styles/office:styles/style:style[2]'; + $this->assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test text run paragraph style using unnamed style + */ + public function testTextRunUnnamed() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $parstyle1 = array('align' => 'start'); + $parstyle2 = array('align' => 'end'); + $section = $phpWord->addSection(); + $trx = $section->addTextRun($parstyle1); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, $parstyle2); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, $parstyle2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('P1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[9]"; + $this->assertEquals('P4', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + $this->assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/Style/SectionTest.php b/tests/PhpWord/Writer/ODText/Style/SectionTest.php new file mode 100644 index 00000000..d471c7f0 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/SectionTest.php @@ -0,0 +1,249 @@ +addFontStyle('hdrstyle1', array('name' => 'Courier New', 'size' => 8)); + $section = $phpWord->addSection(array('paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins)); + $header = $section->createHeader(); + $phpWord->addParagraphStyle('centerheader', array('align' => 'center')); + $header->addText('Centered Header', 'hdrstyle1', 'centerheader'); + $footer = $section->createFooter(); + $sizew = $section->getStyle()->getPageSizeW(); + $sizel = $section->getStyle()->getMarginLeft(); + $sizer = $section->getStyle()->getMarginRight(); + $footerwidth = $sizew - $sizel - $sizer; + $phpWord->addParagraphStyle( + 'footerTab', + array( + 'tabs' => array( + new \PhpOffice\PhpWord\Style\Tab('center', (int) ($footerwidth / 2)), + new \PhpOffice\PhpWord\Style\Tab('right', (int) $footerwidth), + ), + ) + ); + $textrun = $footer->addTextRun('footerTab'); + $textrun->addText('Left footer', 'hdrstyle1'); + $textrun->addText("\t", 'hdrstyle1'); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle('hdrstyle1'); + $textrun->addText("\t", 'hdrstyle1'); + $textrun->addText('Page ', 'hdrstyle1'); + $fld = $textrun->addField('PAGE'); + $fld->setFontStyle('hdrstyle1'); + $textrun->addText(' of ', 'hdrstyle1'); + $fld = $textrun->addField('NUMPAGES'); + $fld->setFontStyle('hdrstyle1'); + $section->addText('First page'); + $section->addPageBreak(); + $section->addText('Second page'); + $section->addPageBreak(); + $section->addText('Third page'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:automatic-styles'; + $element = "$s2a/style:page-layout/style:page-layout-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $s2s = '/office:document-styles/office:styles'; + $element = "$s2s/style:style[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:text-properties"; + $this->assertTrue($doc->elementExists($tprop)); + $this->assertEquals('Courier New', $doc->getElementAttribute($tprop, 'style:font-name')); + + $element = "$s2s/style:style[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('centerheader', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($tprop)); + $this->assertEquals('center', $doc->getElementAttribute($tprop, 'fo:text-align')); + + $element = "$s2s/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('footerTab', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:paragraph-properties/style:tab-stops"; + $this->assertTrue($doc->elementExists($tprop)); + $tstop = "$tprop/style:tab-stop[1]"; + $this->assertTrue($doc->elementExists($tstop)); + $this->assertEquals('center', $doc->getElementAttribute($tstop, 'style:type')); + $this->assertEquals('3.25in', $doc->getElementAttribute($tstop, 'style:position')); + $tstop = "$tprop/style:tab-stop[2]"; + $this->assertTrue($doc->elementExists($tstop)); + $this->assertEquals('right', $doc->getElementAttribute($tstop, 'style:type')); + $this->assertEquals('6.5in', $doc->getElementAttribute($tstop, 'style:position')); + + $s2s = '/office:document-styles/office:master-styles/style:master-page/style:footer/text:p'; + $this->assertTrue($doc->elementExists($s2s)); + $element = "$s2s/text:span[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('Left footer', $doc->getElement($element)->nodeValue); + $element = "$s2s/text:span[2]/text:tab"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[3]/text:date"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[4]/text:tab"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[5]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Page', $doc->getElement($element)->nodeValue); + $this->assertTrue($doc->elementExists("$element/text:s")); + $element = "$s2s/text:span[6]/text:page-number"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[7]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('of', $doc->getElement($element)->nodeValue); + $this->assertTrue($doc->elementExists("$element/text:s")); + $this->assertTrue($doc->elementExists("$element/text:s[2]")); + $element = "$s2s/text:span[8]/text:page-count"; + $this->assertTrue($doc->elementExists($element)); + } + + /** + * Test HideErrors + */ + public function testHideErrors() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setHideGrammaticalErrors(true); + $phpWord->getSettings()->setHideSpellingErrors(true); + $phpWord->getSettings()->setThemeFontLang(new \PhpOffice\PhpWord\Style\Language('en-US')); + $phpWord->getSettings()->getThemeFontLang()->setLangId(\PhpOffice\PhpWord\Style\Language::EN_US_ID); + $section = $phpWord->addSection(); + $section->addText('Here is a paragraph with some speling errorz'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:default-style/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'fo:country')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex')); + } + + /** + * Test SpaceBeforeAfter + */ + public function testMultipleSections() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(array('paperSize' => 'Letter', 'Orientation' => 'portrait')); + $section->addText('This section uses Letter paper in portrait orientation.'); + $section = $phpWord->addSection(array('paperSize' => 'A4', 'Orientation' => 'landscape', 'pageNumberingStart' => '9')); + $header = $section->createHeader(); + $header->addField('PAGE'); + $section->addText('This section uses A4 paper in landscape orientation. It should have a page break beforehand. It artificially starts on page 9.'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $s2t = '/office:document-content/office:body/office:text'; + $this->assertTrue($doc->elementExists($s2a)); + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('SB1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Standard1', $doc->getElementAttribute($element, 'style:master-page-name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('none', $doc->getElementAttribute($element, 'text:display')); + $element = "$s2a/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('SB2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Standard2', $doc->getElementAttribute($element, 'style:master-page-name')); + $elemen2 = "$element/style:paragraph-properties"; + $this->assertEquals('9', $doc->getElementAttribute($elemen2, 'style:page-number')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('none', $doc->getElementAttribute($element, 'text:display')); + + $element = "$s2t/text:section[1]"; + $this->assertTrue($doc->elementExists($element)); + $element .= '/text:p[1]'; + $this->assertEquals('SB1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2t/text:section[2]"; + $this->assertTrue($doc->elementExists($element)); + $element .= '/text:p[1]'; + $this->assertEquals('SB2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:page-layout[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:page-layout-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('portrait', $doc->getElementAttribute($element, 'style:print-orientation')); + + $element = "$s2a/style:page-layout[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:page-layout-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('29.7cm', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('21cm', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('landscape', $doc->getElementAttribute($element, 'style:print-orientation')); + + $s2a = '/office:document-styles/office:master-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/style:master-page[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Standard1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:page-layout-name')); + $element = "$s2a/style:master-page[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Standard2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:page-layout-name')); + } +} diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 02fa7d78..d35f0e3f 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -63,7 +63,12 @@ class TestHelperDOCX $zip->close(); } - return new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + if ($writerName === 'ODText') { + $doc->setDefaultFile('content.xml'); + } + + return $doc; } /** diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bc..41a9d9db 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -50,6 +50,37 @@ class XmlDocument */ private $file; + /** + * Default file name + * + * @var string + */ + private $defaultFile = 'word/document.xml'; + + /** + * Get default file + * + * @return string + */ + public function getDefaultFile() + { + return $this->defaultFile; + } + + /** + * Set default file + * + * @param string $file + * @return string + */ + public function setDefaultFile($file) + { + $temp = $this->defaultFile; + $this->defaultFile = $file; + + return $temp; + } + /** * Create new instance * @@ -66,8 +97,11 @@ class XmlDocument * @param string $file * @return \DOMDocument */ - public function getFileDom($file = 'word/document.xml') + public function getFileDom($file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null !== $this->dom && $file === $this->file) { return $this->dom; } @@ -91,8 +125,11 @@ class XmlDocument * @param string $file * @return \DOMNodeList */ - public function getNodeList($path, $file = 'word/document.xml') + public function getNodeList($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null === $this->dom || $file !== $this->file) { $this->getFileDom($file); } @@ -112,8 +149,11 @@ class XmlDocument * @param string $file * @return \DOMElement */ - public function getElement($path, $file = 'word/document.xml') + public function getElement($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $elements = $this->getNodeList($path, $file); return $elements->item(0); @@ -147,8 +187,12 @@ class XmlDocument * @param string $file * @return string */ - public function getElementAttribute($path, $attribute, $file = 'word/document.xml') + public function getElementAttribute($path, $attribute, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } + return $this->getElement($path, $file)->getAttribute($attribute); } @@ -159,8 +203,11 @@ class XmlDocument * @param string $file * @return string */ - public function elementExists($path, $file = 'word/document.xml') + public function elementExists($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $nodeList = $this->getNodeList($path, $file); return $nodeList->length != 0; @@ -173,8 +220,11 @@ class XmlDocument * @param string $file * @return string */ - public function printXml($path = '/', $file = 'word/document.xml') + public function printXml($path = '/', $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $element = $this->getElement($path, $file); if ($element instanceof \DOMDocument) { $element->formatOutput = true; From cfa29cc1c2bb746f1413ada91b748e9712bd003b Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 5 Jan 2020 13:52:20 -0800 Subject: [PATCH 02/58] Applying Scrutinizer Suggestions I do not understand one suggestion, and I believe one is wrong. I will add comments to my ticket once this is pushed. One that I can discuss up front PhpWord/Style/Paragraph indicates that Indentation must be of type \PhpOffice\PhpWord\Style\Indentation, but it can also be null. My test for instanceof ... is one of the Scrutinizer reports. I did not change PhpWord/Style/Paragraph, but this commit does so by updating @var for indentation. --- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText/Element/Field.php | 4 +- src/PhpWord/Writer/ODText/Part/Content.php | 7 ++-- src/PhpWord/Writer/ODText/Part/Styles.php | 42 +++++++------------ src/PhpWord/Writer/ODText/Style/Paragraph.php | 6 +-- 5 files changed, 24 insertions(+), 37 deletions(-) diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 72f0f809..580ef54a 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -85,7 +85,7 @@ class Paragraph extends Border /** * Indentation * - * @var \PhpOffice\PhpWord\Style\Indentation + * @var \PhpOffice\PhpWord\Style\Indentation|null */ private $indentation; diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index c95139ac..f7a74c1d 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -41,7 +41,7 @@ class Field extends Text $type = strtolower($element->getType()); switch ($type) { - case 'date': // Owen 2020-01-02 + case 'date': case 'page': case 'numpages': $this->writeDefault($element, $type); @@ -61,7 +61,7 @@ class Field extends Text } } switch ($type) { - case 'date': // Owen 2019-01-02 + case 'date': $xmlWriter->startElement('text:date'); $xmlWriter->writeAttribute('text:fixed', 'false'); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 8eaad40f..ea4c87d2 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -186,7 +186,8 @@ class Content extends AbstractPart $styleWriter->write(); $sects = $this->getParentWriter()->getPhpWord()->getSections(); - for ($i = 0; $i < count($sects); ++$i) { + $countsects = count($sects); + for ($i = 0; $i < $countsects; ++$i) { $iplus1 = $i + 1; $style = new Paragraph(); $style->setStyleName("SB$iplus1"); @@ -297,7 +298,7 @@ class Content extends AbstractPart /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text $element + * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\TextRun $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ @@ -331,7 +332,7 @@ class Content extends AbstractPart } else { $element->setParagraphStyle($name); } - } elseif (is_string($paragraphStyle)) { + } else { $paragraphStyleCount++; $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 862f4b2a..bcd57ad5 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -140,16 +140,12 @@ class Styles extends AbstractPart /** * Convert int in twips to inches/cm then to string and append unit * - * @param int $twips - * @param string $dflt + * @param int|float $twips * @param float $factor * return string */ - private static function cvttwiptostr($twips, $dflt, $factor = 1.0) // Owen 2019-08-06 + private static function cvttwiptostr($twips, $factor = 1.0) { - if ($twips === null) { - return $dflt; - } $ins = (string) ($twips * $factor / Converter::INCH_TO_TWIP) . 'in'; $cms = (string) ($twips * $factor * Converter::INCH_TO_CM / Converter::INCH_TO_TWIP) . 'cm'; @@ -161,10 +157,11 @@ class Styles extends AbstractPart * * @param \PhpOffice\Common\XMLWriter $xmlWriter */ - private function writePageLayout(XMLWriter $xmlWriter) // Owen 2019-06-19 + private function writePageLayout(XMLWriter $xmlWriter) { $sections = $this->getParentWriter()->getPhpWord()->getSections(); - for ($i = 0; $i < count($sections); ++$i) { + $countsects = count($sections); + for ($i = 0; $i < $countsects; ++$i) { $this->writePageLayoutIndiv($xmlWriter, $sections[$i], $i + 1); } } @@ -189,23 +186,13 @@ class Styles extends AbstractPart } else { $botfactor = 1.0; } - $pwidth = '21.001cm'; - $pheight = '29.7cm'; - $orient = 'portrait'; - $mtop = $mleft = $mright = '2.501cm'; - $mbottom = '2cm'; - if ($sty instanceof \PhpOffice\PhpWord\Style\Section) { - $ori = $sty->getOrientation(); - if ($ori !== null) { - $orient = $ori; - } - $pwidth = self::cvttwiptostr($sty->getPageSizeW(), $pwidth); - $pheight = self::cvttwiptostr($sty->getPageSizeH(), $pheight); - $mtop = self::cvttwiptostr($sty->getMarginTop(), $mtop, $topfactor); - $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $mbottom, $botfactor); - $mleft = self::cvttwiptostr($sty->getMarginRight(), $mleft); - $mright = self::cvttwiptostr($sty->getMarginLeft(), $mright); - } + $orient = $sty->getOrientation(); + $pwidth = self::cvttwiptostr($sty->getPageSizeW()); + $pheight = self::cvttwiptostr($sty->getPageSizeH()); + $mtop = self::cvttwiptostr($sty->getMarginTop(), $topfactor); + $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $botfactor); + $mleft = self::cvttwiptostr($sty->getMarginRight()); + $mright = self::cvttwiptostr($sty->getMarginLeft()); $xmlWriter->startElement('style:page-layout'); $xmlWriter->writeAttribute('style:name', "Mpm$sectionNbr"); @@ -253,7 +240,7 @@ class Styles extends AbstractPart $xmlWriter->endElement(); // style:header-style $xmlWriter->startElement('style:footer-style'); - if ($botfactor < 1.0) { // Owen 2019-08-03 + if ($botfactor < 1.0) { $xmlWriter->startElement('style:header-footer-properties'); $xmlWriter->writeAttribute('fo:min-height', $mbottom); $xmlWriter->writeAttribute('fo:margin-top', $mbottom); @@ -275,7 +262,8 @@ class Styles extends AbstractPart $xmlWriter->startElement('office:master-styles'); $sections = $this->getParentWriter()->getPhpWord()->getSections(); - for ($i = 0; $i < count($sections); ++$i) { + $countsects = count($sections); + for ($i = 0; $i < $countsects; ++$i) { $iplus1 = $i + 1; $xmlWriter->startElement('style:master-page'); $xmlWriter->writeAttribute('style:name', "Standard$iplus1"); diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 555a4825..be974e72 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -56,9 +56,7 @@ class Paragraph extends AbstractStyle $styleAuto = true; $mpm = 'Standard' . substr($styleName, 2); $psn = $style->getNumLevel(); - if (is_numeric($psn)) { - $pagestart = (int) $psn; - } + $pagestart = $psn; } elseif (substr($styleName, 0, 2) === 'HD') { $styleAuto = true; $psm = 'Heading_' . substr($styleName, 2); @@ -117,7 +115,7 @@ class Paragraph extends AbstractStyle $xmlWriter->writeAttributeIf($temp !== '', 'fo:text-align', $temp); $temp = $style->getLineHeight(); $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%')); - $xmlWriter->writeAttributeIf($style->getPageBreakBefore() === true, 'fo:break-before', 'page'); + $xmlWriter->writeAttributeIf($style->hasPageBreakBefore() === true, 'fo:break-before', 'page'); $tabs = $style->getTabs(); if ($tabs !== null && count($tabs) > 0) { From 46c41c5ac182f8eadc9493f4089ca740d034c6e4 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 5 Jan 2020 15:05:00 -0800 Subject: [PATCH 03/58] More Scrutinizer Changes Still one report that I don't understand at all, and one I'm not sure of. --- src/PhpWord/Writer/ODText/Element/TextRun.php | 1 + src/PhpWord/Writer/ODText/Part/Content.php | 35 +++++++++++++++++-- src/PhpWord/Writer/ODText/Style/Paragraph.php | 3 +- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index cde996f6..9a005773 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -33,6 +33,7 @@ class TextRun extends Text $element = $this->getElement(); $xmlWriter->startElement('text:p'); + /** @scrutinizer ignore-call */ $pStyle = $element->getParagraphStyle(); if (!is_string($pStyle)) { $pStyle = 'Normal'; diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index ea4c87d2..9d6a50c4 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -266,7 +266,7 @@ class Content extends AbstractPart $elements = $container->getElements(); foreach ($elements as $element) { if ($element instanceof TextRun) { - $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + $this->getElementStyleTextRun($element, $paragraphStyleCount); $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); @@ -298,7 +298,7 @@ class Content extends AbstractPart /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\TextRun $element + * @param \PhpOffice\PhpWord\Element\Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ @@ -341,6 +341,37 @@ class Content extends AbstractPart } } + /** + * Get style of individual element + * + * @param \PhpOffice\PhpWord\Element\TextRun $element + * @param int $paragraphStyleCount + */ + private function getElementStyleTextRun(&$element, &$paragraphStyleCount) + { + $paragraphStyle = $element->getParagraphStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + if ($paragraphStyle instanceof Paragraph) { + // Paragraph + $name = $paragraphStyle->getStyleName(); + if (!$name) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } else { + $element->setParagraphStyle($name); + } + } else { + $paragraphStyleCount++; + $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; + $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle($parstylename); + } + } + /** * Finds all tracked changes * diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index be974e72..9d38de86 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -134,7 +134,8 @@ class Paragraph extends AbstractStyle //Indentation $indent = $style->getIndentation(); - if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + //if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + if (!empty($indent)) { $marg = $indent->getLeft(); $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-left', (string) ($marg / Converter::INCH_TO_TWIP) . 'in'); $marg = $indent->getRight(); From d5149b2867a6887e9b35523194f8a379194099f4 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 6 Feb 2020 19:20:13 -0800 Subject: [PATCH 04/58] Coveralls Changes Changes to improve test coverage based on Coveralls report. --- src/PhpWord/Writer/ODText/Part/Content.php | 19 ++- tests/PhpWord/Shared/ConverterTest.php | 3 + .../Writer/ODText/Element/ImageTest.php | 5 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- .../Writer/ODText/Part/AbstractPartTest.php | 1 - .../Writer/ODText/Part/ContentTest.php | 1 - .../PhpWord/Writer/ODText/Style/FontTest.php | 116 ++++++++++++++++++ .../Writer/ODText/Style/ParagraphTest.php | 31 +++++ 8 files changed, 166 insertions(+), 12 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 9d6a50c4..88d7acbd 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; @@ -270,6 +271,8 @@ class Content extends AbstractPart $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + } elseif ($element instanceof Field) { + $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Image) { $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); @@ -298,14 +301,18 @@ class Content extends AbstractPart /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text $element + * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\Field $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ - private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) + private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount) { $fontStyle = $element->getFontStyle(); - $paragraphStyle = $element->getParagraphStyle(); + if (method_exists($element, 'getParagraphStyle')) { + $paragraphStyle = $element->getParagraphStyle(); + } else { + $paragraphStyle = null; + } $phpWord = $this->getParentWriter()->getPhpWord(); if ($fontStyle instanceof Font) { @@ -332,7 +339,7 @@ class Content extends AbstractPart } else { $element->setParagraphStyle($name); } - } else { + } elseif ($paragraphStyle) { $paragraphStyleCount++; $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); @@ -347,7 +354,7 @@ class Content extends AbstractPart * @param \PhpOffice\PhpWord\Element\TextRun $element * @param int $paragraphStyleCount */ - private function getElementStyleTextRun(&$element, &$paragraphStyleCount) + private function getElementStyleTextRun($element, &$paragraphStyleCount) { $paragraphStyle = $element->getParagraphStyle(); $phpWord = $this->getParentWriter()->getPhpWord(); @@ -363,7 +370,7 @@ class Content extends AbstractPart } else { $element->setParagraphStyle($name); } - } else { + } elseif ($paragraphStyle) { $paragraphStyleCount++; $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 15be8ec1..39ffe090 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -135,5 +135,8 @@ class ConverterTest extends \PHPUnit\Framework\TestCase $this->assertEquals(120, Converter::cssToPoint('10pc')); $this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001); $this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001); + $this->assertEquals(40, Converter::cssToPixel('30pt')); + $this->assertEquals(1.27, Converter::cssToCm('36pt')); + $this->assertEquals(127000, Converter::cssToEmu('10pt')); } } diff --git a/tests/PhpWord/Writer/ODText/Element/ImageTest.php b/tests/PhpWord/Writer/ODText/Element/ImageTest.php index bc861104..2e0fdeef 100644 --- a/tests/PhpWord/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWord/Writer/ODText/Element/ImageTest.php @@ -21,10 +21,9 @@ use PhpOffice\PhpWord\Style\Image; use PhpOffice\PhpWord\TestHelperDOCX; /** - * Test class for PhpOffice\PhpWord\Writer\Word2007\Style\Font + * Test class for PhpOffice\PhpWord\Writer\ODText\Element\Image * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Style\Frame - * @runTestsInSeparateProcesses + * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Element\Image */ class ImageTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 500ee247..afad150d 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -39,7 +39,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase */ public function testUnmatchedElements() { - $elements = array('Image', 'Link', 'Table', 'Text', 'Title'); + $elements = array('Image', 'Link', 'Table', 'Text', 'Title', 'Field'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element\\' . $element; $xmlWriter = new XMLWriter(); diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 51d893d2..3f0c8129 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -23,7 +23,6 @@ use PhpOffice\PhpWord\Writer\ODText; * Test class for PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart * * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart - * @runTestsInSeparateProcesses */ class AbstractPartTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 34eb8068..55d1a00e 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -25,7 +25,6 @@ use PhpOffice\PhpWord\TestHelperDOCX; * Test class for PhpOffice\PhpWord\Writer\ODText\Part\Content * * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\Content - * @runTestsInSeparateProcesses */ class ContentTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php index 5306c6b0..f1224179 100644 --- a/tests/PhpWord/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -73,6 +74,61 @@ class FontTest extends \PHPUnit\Framework\TestCase $this->assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue); } + public function providerAllNamedColors() + { + return array( + array(Font::FGCOLOR_YELLOW, 'FFFF00'), + array(Font::FGCOLOR_LIGHTGREEN, '90EE90'), + array(Font::FGCOLOR_CYAN, '00FFFF'), + array(Font::FGCOLOR_MAGENTA, 'FF00FF'), + array(Font::FGCOLOR_BLUE, '0000FF'), + array(Font::FGCOLOR_RED, 'FF0000'), + array(Font::FGCOLOR_DARKBLUE, '00008B'), + array(Font::FGCOLOR_DARKCYAN, '008B8B'), + array(Font::FGCOLOR_DARKGREEN, '006400'), + array(Font::FGCOLOR_DARKMAGENTA, '8B008B'), + array(Font::FGCOLOR_DARKRED, '8B0000'), + array(Font::FGCOLOR_DARKYELLOW, '8B8B00'), + array(Font::FGCOLOR_DARKGRAY, 'A9A9A9'), + array(Font::FGCOLOR_LIGHTGRAY, 'D3D3D3'), + array(Font::FGCOLOR_BLACK, '000000'), + array('unknow', 'unknow'), + array('unknown', 'unknown'), + ); + } + + /** + * @dataProvider providerAllNamedColors + * + * @param string $namedColor + * @param string $rgbColor + */ + public function testAllNamedColors($namedColor, $rgbColor) + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This is red (800) in rtf/html, default in docx/odt', array('color' => '800')); + $section->addText('This should be cyanish (008787)', array('color' => '008787')); + $section->addText($namedColor, array('color' => $namedColor)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals("#$rgbColor", $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals($namedColor, $doc->getElement($span)->nodeValue); + } + /** * Test noproof */ @@ -128,4 +184,64 @@ class FontTest extends \PHPUnit\Framework\TestCase $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); $this->assertEquals('Noproof is false', $doc->getElement($span)->nodeValue); } + + /** + * Test using object with a name as font style for addText + */ + public function testNamedStyleAsObject() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $named = $phpWord->addFontStyle('namedobject', array('color' => '008787')); + $section = $phpWord->addSection(); + $section->addText('Let us see what color we wind up with', $named); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + $element = "$s2t/text:p[2]/text:span"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('namedobject', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test supplying field font style as array or object or string + */ + public function testFieldStyles() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addFontStyle('namedstyle', array('color' => '800000')); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle('namedstyle'); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle(array('color' => '008000')); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $font = new \PhpOffice\PhpWord\Style\Font(); + $font->setColor('000080'); + $fld->setFontStyle($font); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $s2t = '/office:document-content/office:body/office:text/text:section'; + + $element = "$s2a/style:style[5]"; + $this->assertEquals('T1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('#008000', $doc->getElementAttribute("$element/style:text-properties", 'fo:color')); + $element = "$s2a/style:style[7]"; + $this->assertEquals('T2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('#000080', $doc->getElementAttribute("$element/style:text-properties", 'fo:color')); + + $element = "$s2t/text:p[2]/text:span"; + $this->assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[3]/text:span"; + $this->assertEquals('T1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[4]/text:span"; + $this->assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + } } diff --git a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php index 0e9948cf..9ddb5fe1 100644 --- a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php @@ -431,4 +431,35 @@ class ParagraphTest extends \PHPUnit\Framework\TestCase $element = "$s2a/text:p[3]"; $this->assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name')); } + + /** + * Test Empty font and paragraph styles + */ + public function testEmptyFontAndParagraphStyles() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $phpWord->addFontStyle('namedfont', array('name' => 'Courier New', 'size' => 8)); + $phpWord->addParagraphStyle('namedpar', array('lineHeight' => 1.08)); + $section->addText('Empty Font Style and Empty Paragraph Style', '', ''); + $section->addText('Named Font Style and Empty Paragraph Style', 'namedfont', ''); + $section->addText('Empty Font Style and Named Paragraph Style', '', 'namedpar'); + $section->addText('Named Font Style and Named Paragraph Style', 'namedfont', 'namedpar'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals(5, $doc->getElementAttribute("$element/text:s", 'text:c')); + $this->assertFalse($doc->elementExists("$element/text:span")); + $element = "$s2a/text:p[3]"; + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name')); + $element = "$s2a/text:p[4]"; + $this->assertEquals('P1_namedpar', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertFalse($doc->elementExists("$element/text:span")); + $element = "$s2a/text:p[5]"; + $this->assertEquals('P2_namedpar', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name')); + } } From 677e042c3a13b51c1f90529e18c1ad569b3c9695 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 6 Feb 2020 20:41:40 -0800 Subject: [PATCH 05/58] Scrutinizer Workaroun Attempt to work around demonstrably incorrect Scrutinizer analysis (flags code as bug because "condition is always false" even though Coveralls reports that code which would be executed only if condition is true is indeed executed). --- src/PhpWord/Writer/ODText/Element/Title.php | 17 ++++++++-- src/PhpWord/Writer/ODText/Part/Content.php | 36 +++++++++++++++++---- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 99153b5e..98ddbbf4 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -39,8 +39,7 @@ class Title extends AbstractElement $hdname = 'HD'; $sect = $element->getParent(); if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { - $elems = $sect->getElements(); - if ($elems[0] === $element) { + if (self::compareToFirstElement($element, $sect->getElements())) { $hdname = 'HE'; } } @@ -63,4 +62,18 @@ class Title extends AbstractElement $xmlWriter->endElement(); // text:span $xmlWriter->endElement(); // text:h } + + /** + * Test if element is same as first element in array + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $elem + * + * @param \PhpOffice\PhpWord\Element\AbstractElement[] $elemarray + * + * @return bool + */ + private static function compareToFirstElement($elem, $elemarray) + { + return $elem === $elemarray[0]; + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 88d7acbd..f0e60441 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -272,7 +272,7 @@ class Content extends AbstractPart } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Field) { - $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + $this->getElementStyleField($element, $fontStyleCount); } elseif ($element instanceof Image) { $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); @@ -301,18 +301,14 @@ class Content extends AbstractPart /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\Field $element + * @param \PhpOffice\PhpWord\Element\Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount) { $fontStyle = $element->getFontStyle(); - if (method_exists($element, 'getParagraphStyle')) { - $paragraphStyle = $element->getParagraphStyle(); - } else { - $paragraphStyle = null; - } + $paragraphStyle = $element->getParagraphStyle(); $phpWord = $this->getParentWriter()->getPhpWord(); if ($fontStyle instanceof Font) { @@ -348,6 +344,32 @@ class Content extends AbstractPart } } + /** + * Get font style of individual field element + * + * @param \PhpOffice\PhpWord\Element\Field $element + * @param int $paragraphStyleCount + * @param int $fontStyleCount + */ + private function getElementStyleField($element, &$fontStyleCount) + { + $fontStyle = $element->getFontStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + if ($fontStyle instanceof Font) { + $name = $fontStyle->getStyleName(); + if (!$name) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle, null); + $style->setAuto(); + $style->setParagraph(null); + $element->setFontStyle("T{$fontStyleCount}"); + } else { + $element->setFontStyle($name); + } + } + } + /** * Get style of individual element * From 4e347b33d7fd73668363c5bebaec3c7a110b9b88 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 6 Feb 2020 23:34:24 -0800 Subject: [PATCH 06/58] One Additional Coveralls Test Cover one line previously omitted from coverage. --- tests/PhpWord/Writer/ODText/Style/FontTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php index f1224179..22a7151c 100644 --- a/tests/PhpWord/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -209,7 +209,7 @@ class FontTest extends \PHPUnit\Framework\TestCase public function testFieldStyles() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); - $phpWord->addFontStyle('namedstyle', array('color' => '800000')); + $namedstyle = $phpWord->addFontStyle('namedstyle', array('color' => '800000')); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); $fld = $textrun->addField('DATE'); @@ -222,6 +222,9 @@ class FontTest extends \PHPUnit\Framework\TestCase $font = new \PhpOffice\PhpWord\Style\Font(); $font->setColor('000080'); $fld->setFontStyle($font); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle($namedstyle); $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); $s2a = '/office:document-content/office:automatic-styles'; @@ -243,5 +246,7 @@ class FontTest extends \PHPUnit\Framework\TestCase $element = "$s2t/text:p[4]/text:span"; $this->assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name')); $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[5]/text:span"; + $this->assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name')); } } From 41a5b74f93ec919fcdefc59ffd6defcc84ab3ff2 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 16 Apr 2020 23:30:27 -0700 Subject: [PATCH 07/58] Make Default Paper Configurable Each section currently has a hard-coded default paper of A4. It would make sense to allow the user to set this default, and specify it in a configuration file, just as is done with default font name and size. --- docs/general.rst | 10 ++ phpword.ini.dist | 4 + src/PhpWord/Settings.php | 34 ++++++ src/PhpWord/Style/Section.php | 6 +- tests/PhpWord/SettingsTest.php | 108 +++++++++++++++++- .../AbstractWebServerEmbeddedTest.php | 21 +++- 6 files changed, 177 insertions(+), 6 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index f40a08c3..d4b9b99c 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -130,6 +130,16 @@ To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord c \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); +Default Paper +~~~~~~~~~~~~~ + +By default, all sections of the document will print on A4 paper. +You can alter the default paper by using the following function: + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setDefaultPaper('Letter'); + Default font ~~~~~~~~~~~~ diff --git a/phpword.ini.dist b/phpword.ini.dist index 0f4cc358..f3f66dbe 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -14,3 +14,7 @@ outputEscapingEnabled = false defaultFontName = Arial defaultFontSize = 10 + +[Paper] + +defaultPaper = "A4" diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 8de1a8df..c493132f 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -70,6 +70,7 @@ class Settings const DEFAULT_FONT_SIZE = 10; const DEFAULT_FONT_COLOR = '000000'; const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs + const DEFAULT_PAPER = 'A4'; /** * Compatibility option for XMLWriter @@ -119,6 +120,12 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** + * Default paper + * @var int + */ + private static $defaultPaper = self::DEFAULT_PAPER; + /** * The user defined temporary directory. * @@ -432,6 +439,33 @@ class Settings return $config; } + /** + * Get default paper + * + * @return string + */ + public static function getDefaultPaper() + { + return self::$defaultPaper; + } + + /** + * Set default paper + * + * @param string $value + * @return bool + */ + public static function setDefaultPaper($value) + { + if (is_string($value) && trim($value) !== '') { + self::$defaultPaper = $value; + + return true; + } + + return false; + } + /** * Return the compatibility option used by the XMLWriter * diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index ff9b0be0..697add74 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\VerticalJc; /** @@ -200,8 +201,11 @@ class Section extends Border * @param string $value * @return self */ - public function setPaperSize($value = 'A4') + public function setPaperSize($value = '') { + if (!$value) { + $value = Settings::getDefaultPaper(); + } if ($this->paper === null) { $this->paper = new Paper(); } diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index afe59549..748ec71b 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -25,6 +25,45 @@ namespace PhpOffice\PhpWord; */ class SettingsTest extends \PHPUnit\Framework\TestCase { + private $compatibility; + private $defaultFontSize; + private $defaultFontName; + private $defaultPaper; + private $measurementUnit; + private $outputEscapingEnabled; + private $pdfRendererName; + private $pdfRendererPath; + private $tempDir; + private $zipClass; + + public function setUp() + { + $this->compatibility = Settings::hasCompatibility(); + $this->defaultFontSize = Settings::getDefaultFontSize(); + $this->defaultFontName = Settings::getDefaultFontName(); + $this->defaultPaper = Settings::getDefaultPaper(); + $this->measurementUnit = Settings::getMeasurementUnit(); + $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled(); + $this->pdfRendererName = Settings::getPdfRendererName(); + $this->pdfRendererPath = Settings::getPdfRendererPath(); + $this->tempDir = Settings::getTempDir(); + $this->zipClass = Settings::getZipClass(); + } + + public function tearDown() + { + Settings::setCompatibility($this->compatibility); + Settings::setDefaultFontSize($this->defaultFontSize); + Settings::setDefaultFontName($this->defaultFontName); + Settings::setDefaultPaper($this->defaultPaper); + Settings::setMeasurementUnit($this->measurementUnit); + Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); + Settings::setPdfRendererName($this->pdfRendererName); + Settings::setPdfRendererPath($this->pdfRendererPath); + Settings::setTempDir($this->tempDir); + Settings::setZipClass($this->zipClass); + } + /** * Test set/get compatibity option */ @@ -35,14 +74,28 @@ class SettingsTest extends \PHPUnit\Framework\TestCase $this->assertFalse(Settings::hasCompatibility()); } + /** + * Test set/get outputEscapingEnabled option + */ + public function testSetGetOutputEscapingEnabled() + { + $this->assertFalse(Settings::isOutputEscapingEnabled()); + Settings::setOutputEscapingEnabled(true); + $this->assertTrue(Settings::isOutputEscapingEnabled()); + } + /** * Test set/get zip class */ public function testSetGetZipClass() { $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); - $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); $this->assertFalse(Settings::setZipClass('foo')); + $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); + $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); + $this->assertEquals(Settings::getZipClass(), Settings::PCLZIP); + $this->assertFalse(Settings::setZipClass('foo')); + $this->assertEquals(Settings::getZipClass(), Settings::PCLZIP); } /** @@ -57,6 +110,7 @@ class SettingsTest extends \PHPUnit\Framework\TestCase $this->assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName()); $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); $this->assertFalse(Settings::setPdfRendererPath('dummy/path')); + $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); } /** @@ -65,8 +119,12 @@ class SettingsTest extends \PHPUnit\Framework\TestCase public function testSetGetMeasurementUnit() { $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); - $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH)); $this->assertFalse(Settings::setMeasurementUnit('foo')); + $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); + $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH)); + $this->assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit()); + $this->assertFalse(Settings::setMeasurementUnit('foo')); + $this->assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit()); } /** @@ -99,8 +157,12 @@ class SettingsTest extends \PHPUnit\Framework\TestCase public function testSetGetDefaultFontName() { $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); - $this->assertTrue(Settings::setDefaultFontName('Times New Roman')); $this->assertFalse(Settings::setDefaultFontName(' ')); + $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); + $this->assertTrue(Settings::setDefaultFontName('Times New Roman')); + $this->assertEquals('Times New Roman', Settings::getDefaultFontName()); + $this->assertFalse(Settings::setDefaultFontName(' ')); + $this->assertEquals('Times New Roman', Settings::getDefaultFontName()); } /** @@ -109,8 +171,35 @@ class SettingsTest extends \PHPUnit\Framework\TestCase public function testSetGetDefaultFontSize() { $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); - $this->assertTrue(Settings::setDefaultFontSize(12)); $this->assertFalse(Settings::setDefaultFontSize(null)); + $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); + $this->assertTrue(Settings::setDefaultFontSize(12)); + $this->assertEquals(12, Settings::getDefaultFontSize()); + $this->assertFalse(Settings::setDefaultFontSize(null)); + $this->assertEquals(12, Settings::getDefaultFontSize()); + } + + /** + * Test set/get default paper + */ + public function testSetGetDefaultPaper() + { + $dflt = Settings::DEFAULT_PAPER; + $chng = ($dflt === 'A4') ? 'Letter' : 'A4'; + $doc = new PhpWord(); + $this->assertEquals($dflt, Settings::getDefaultPaper()); + $sec1 = $doc->addSection(); + $this->assertEquals($dflt, $sec1->getStyle()->getPaperSize()); + $this->assertFalse(Settings::setDefaultPaper('')); + $this->assertEquals($dflt, Settings::getDefaultPaper()); + $this->assertTrue(Settings::setDefaultPaper($chng)); + $this->assertEquals($chng, Settings::getDefaultPaper()); + $sec2 = $doc->addSection(); + $this->assertEquals($chng, $sec2->getStyle()->getPaperSize()); + $sec3 = $doc->addSection(array('paperSize' => 'Legal')); + $this->assertEquals('Legal', $sec3->getStyle()->getPaperSize()); + $this->assertFalse(Settings::setDefaultPaper('')); + $this->assertEquals($chng, Settings::getDefaultPaper()); } /** @@ -126,6 +215,7 @@ class SettingsTest extends \PHPUnit\Framework\TestCase 'defaultFontName' => 'Arial', 'defaultFontSize' => 10, 'outputEscapingEnabled' => false, + 'defaultPaper' => 'A4', ); // Test default value @@ -133,6 +223,16 @@ class SettingsTest extends \PHPUnit\Framework\TestCase // Test with valid file $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../phpword.ini.dist')); + foreach ($expected as $key => $value) { + if ($key === 'compatibility') { + $meth = 'hasCompatibility'; + } elseif ($key === 'outputEscapingEnabled') { + $meth = 'isOutputEscapingEnabled'; + } else { + $meth = 'get' . ucfirst($key); + } + $this->assertEquals(Settings::$meth(), $value); + } // Test with invalid file $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist')); diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe..25fe836a 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,26 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From 6da3fd3c066bd004e314ea3a138b304b983b2646 Mon Sep 17 00:00:00 2001 From: oleibman Date: Thu, 16 Apr 2020 23:55:24 -0700 Subject: [PATCH 08/58] Correct Scrutinizer Warning Type was declared incorrectly in comment. --- src/PhpWord/Settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index c493132f..80e512d2 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -122,7 +122,7 @@ class Settings /** * Default paper - * @var int + * @var string */ private static $defaultPaper = self::DEFAULT_PAPER; From ba3d6162825d23a999064dbc856410912e86939b Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 23 Apr 2020 17:25:56 -0700 Subject: [PATCH 09/58] Improve Test Coverage Coverage for Writer/ODText is now 100%. --- src/PhpWord/Element/Section.php | 2 + src/PhpWord/Writer/ODText/Element/Text.php | 10 +- tests/PhpWord/Element/ImageTest.php | 4 +- tests/PhpWord/Writer/ODText/ElementTest.php | 100 ++++++++++++++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index b6da9f3b..caf2ca27 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -157,6 +157,8 @@ class Section extends AbstractContainer * @deprecated Use the `getFootnoteProperties` method instead * * @return FootnoteProperties + * + * @codeCoverageIgnore */ public function getFootnotePropoperties() { diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 2bf9908d..464d2777 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -42,12 +42,12 @@ class Text extends AbstractElement // @todo Commented for TextRun. Should really checkout this value // $fStyleIsObject = ($fontStyle instanceof Font) ? true : false; - $fStyleIsObject = false; + //$fStyleIsObject = false; - if ($fStyleIsObject) { - // Don't never be the case, because I browse all sections for cleaning all styles not declared - throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); - } + //if ($fStyleIsObject) { + // Don't never be the case, because I browse all sections for cleaning all styles not declared + // throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); + //} if (!$this->withoutP) { $xmlWriter->startElement('text:p'); // text:p diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index f56d0794..e83be708 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -77,10 +77,12 @@ class ImageTest extends AbstractWebServerEmbeddedTest foreach ($images as $imageData) { list($source, $type, $extension, $createFunction, $imageFunction) = $imageData; + $nam = ucfirst(strtok($source, '.')); $source = __DIR__ . "/../_files/images/{$source}"; - $image = new Image($source); + $image = new Image($source, null, null, $nam); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); $this->assertEquals($source, $image->getSource()); + $this->assertEquals($nam, $image->getName()); $this->assertEquals(md5($source), $image->getMediaId()); $this->assertEquals($type, $image->getImageType()); $this->assertEquals($extension, $image->getImageExtension()); diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index afad150d..eda4568d 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; @@ -187,6 +188,47 @@ class ElementTest extends \PHPUnit\Framework\TestCase $this->assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color')); } + /** + * Test title specified as text run rather than text + */ + public function testTextRunTitle() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle(1, array('name' => 'Times New Roman', 'size' => 18, 'bold' => true)); + $section = $phpWord->addSection(); + $section->addTitle('Text Title', 1); + $section->addText('Text following Text Title'); + $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun->addText('Text Run'); + $textRun->addText(' Title'); + $section->addTitle($textRun, 1); + $section->addText('Text following Text Run Title'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + + $element = "$p2t/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertEquals('Text Title', $doc->getElement($span)->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + $element = "$p2t/text:p[2]/text:span"; + $this->assertEquals('Text following Text Title', $doc->getElement($element)->nodeValue); + + $element = "$p2t/text:h[2]"; + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertEquals('Text Run', $doc->getElement("$span/text:span[1]")->textContent); + $this->assertTrue($doc->elementExists("$span/text:span[2]/text:s")); + $this->assertEquals('Title', $doc->getElement("$span/text:span[2]")->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + $element = "$p2t/text:p[3]/text:span"; + $this->assertEquals('Text following Text Run Title', $doc->getElement($element)->nodeValue); + } + /** * Test correct writing of text with ampersand in it */ @@ -225,4 +267,62 @@ class ElementTest extends \PHPUnit\Framework\TestCase self::assertTrue($doc->elementExists($element, 'content.xml')); self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); } + + /** + * Test tracked changes + */ + public function testTrackedChanges() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + + // New portrait section + $section = $phpWord->addSection(); + $textRun = $section->addTextRun(); + + $text = $textRun->addText('Hello World! Time to '); + + $text = $textRun->addText('wake ', array('bold' => true)); + $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); + + $text = $textRun->addText('up'); + $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); + + $text = $textRun->addText('go to sleep'); + $text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $tcs = '/office:document-content/office:body/office:text/text:tracked-changes'; + $tc1 = "$tcs/text:changed-region[1]"; + $tc1id = $doc->getElementAttribute($tc1, 'text:id'); + $element = "$tc1/text:insertion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Fred', $doc->getElement("$element/dc:creator")->nodeValue); + self::assertTrue($doc->elementExists("$element/dc:date")); + + $tc2 = "$tcs/text:changed-region[2]"; + $tc2id = $doc->getElementAttribute($tc2, 'text:id'); + $element = "$tc2/text:insertion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Fred', $doc->getElement("$element/dc:creator")->nodeValue); + //self::assertTrue($doc->elementExists("$element/dc:date")); + + $tc3 = "$tcs/text:changed-region[3]"; + $tc3id = $doc->getElementAttribute($tc3, 'text:id'); + $element = "$tc3/text:deletion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Barney', $doc->getElement("$element/dc:creator")->nodeValue); + self::assertTrue($doc->elementExists("$element/dc:date")); + + $p2t = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $element = "$p2t/text:span[2]/text:change-start"; + self::AssertEquals($tc1id, $doc->getElementAttribute($element, 'text:change-id')); + $element = "$p2t/text:span[3]/text:change-start"; + self::AssertEquals($tc2id, $doc->getElementAttribute($element, 'text:change-id')); + $element = "$p2t/text:change"; + self::AssertEquals($tc3id, $doc->getElementAttribute($element, 'text:change-id')); + } } From 3738a6806eb4ee1b333b285d8b5c08be7af41ab5 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Mon, 27 Apr 2020 21:29:27 -0700 Subject: [PATCH 10/58] Improve Word2007 Test Coverage After this change, Writer/Word2007 is 100% covered. One source change is required. Writer/Word2007/Style/AbstractStyle has incorrectly searched Measurement Array using in_array (which searches values) rather than array_key_exists (keys). There was no test for this, and now there is. 3 changes in tests/PhpWord/_includes are borrowed from "ODT Changes" (pull request 1796, not yet merged) and "Fix PHPUnit Tests" (pull request 1771, merged after work on this change was started). Writer/Word2007/ElementTest was becoming too unwieldy. Tests for Chart and FormFields were moved to their own members. --- .../Writer/Word2007/Style/AbstractStyle.php | 2 +- .../Writer/Word2007/Element/ChartTest.php | 241 ++++++++++++++++++ .../Writer/Word2007/Element/FormFieldTest.php | 70 +++++ tests/PhpWord/Writer/Word2007/ElementTest.php | 50 +--- .../Writer/Word2007/Part/SettingsTest.php | 27 ++ .../Writer/Word2007/Style/ImageTest.php | 36 +++ .../Writer/Word2007/Style/SectionTest.php | 57 +++++ .../AbstractWebServerEmbeddedTest.php | 21 +- tests/PhpWord/_includes/TestHelperDOCX.php | 7 +- tests/PhpWord/_includes/XmlDocument.php | 62 ++++- 10 files changed, 516 insertions(+), 57 deletions(-) create mode 100644 tests/PhpWord/Writer/Word2007/Element/ChartTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Style/SectionTest.php diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index fcd4aeb6..877ff1db 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -96,7 +96,7 @@ abstract class AbstractStyle ); $unit = Settings::getMeasurementUnit(); $factor = 1; - if (in_array($unit, $factors) && $value != $default) { + if (array_key_exists($unit, $factors) && $value != $default) { $factor = $factors[$unit]; } diff --git a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php new file mode 100644 index 00000000..432d8db8 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php @@ -0,0 +1,241 @@ +outputEscapingEnabled = Settings::isOutputEscapingEnabled(); + } + + /** + * Executed after each method of the class + */ + public function tearDown() + { + Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); + TestHelperDOCX::clear(); + } + + /** + * Test chart elements + */ + public function testChartElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + ); + + $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + foreach ($chartTypes as $chartType) { + $section->addChart($chartType, $categories, $series1, $style); + } + $colorArray = array('FFFFFF', '000000', 'FF0000', '00FF00', '0000FF'); + $numColor = count($colorArray); + $chart = $section->addChart('pie', $categories, $series1, $style); + $chart->getStyle()->setColors($colorArray)->setTitle('3d chart')->set3d(true); + $chart = $section->addChart('stacked_bar', $categories, $series1, $style); + $chart->getStyle()->setColors($colorArray)->setShowLegend(true); + $chart = $section->addChart('scatter', $categories, $series1, $style); + $chart->getStyle()->setMajorTickPosition('cross'); + $section->addChart('scatter', $categories, $series1, $style, 'seriesname'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 0; + foreach ($chartTypes as $chartType) { + ++$index; + $file = "word/charts/chart{$index}.xml"; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + self::assertTrue($doc->elementExists($path, $file), "chart type $chartType"); + } + + $index = 11; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'scatter'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + self::assertEquals('seriesname', $doc->getElement($path . '/c:ser/c:tx/c:strRef/c:strCache/c:pt/c:v')->nodeValue); + + $index = 8; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'pie3D'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + for ($idx = 0; $idx < $numColor; ++$idx) { + $idxp1 = $idx + 1; + $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; + self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "pie3d chart idx=$idx"); + } + + $index = 9; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) { + $idx = $idxp1; // stacked bar chart is shifted + $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; + self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); + } + } + + public function testChartEscapingEnabled() + { + Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $categories = array('A&B', 'C', 'E', 'F', 'G'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart('bar', $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit"; + $element = "$path/c:pt[1]/c:v"; + self::assertEquals('A&B', $doc->getElement($element)->nodeValue); + $element = "$path/c:pt[2]/c:v"; + self::assertEquals('C', $doc->getElement($element)->nodeValue); + } + + public function testChartEscapingDisabled() + { + Settings::setOutputEscapingEnabled(false); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $categories = array('A&B', 'C<D>', 'E', 'F', 'G'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart('bar', $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit"; + $element = "$path/c:pt[1]/c:v"; + self::assertEquals('A&B', $doc->getElement($element)->nodeValue); + $element = "$path/c:pt[2]/c:v"; + self::assertEquals('C', $doc->getElement($element)->nodeValue); + } + + public function testValueAxisTitle() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $chartType = 'line'; + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart($chartType, $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'line'; + $path = '/c:chartSpace/c:chart/c:plotArea'; + $element = "$path/c:{$chartType}Chart"; + self::assertTrue($doc->elementExists($path)); + $element = "$path/c:valAx"; + self::assertTrue($doc->elementExists($element)); + $element .= '/c:title/c:tx/c:rich/a:p/a:r/a:t'; + self::assertEquals('Values', $doc->getElement($element)->nodeValue); + } + + public function testNoAxisLabels() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => false, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $chartType = 'line'; + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart($chartType, $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'line'; + $path = '/c:chartSpace/c:chart/c:plotArea'; + $element = "$path/c:{$chartType}Chart"; + $element = "$path/c:valAx"; + $element .= '/c:tickLblPos'; + self::assertEquals('none', $doc->getElementAttribute($element, 'val')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php new file mode 100644 index 00000000..f3ee1790 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php @@ -0,0 +1,70 @@ +addSection(); + + $section->addFormField('textinput')->setName('MyTextBox'); + $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); + $section->addFormField('checkbox')->setDefault(true); + $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3', '')); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = '/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:textInput")); + $this->assertEquals('MyTextBox', $doc->getElementAttribute("$path/w:name", 'w:val')); + + $path = '/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:checkBox")); + $path = '/w:document/w:body/w:p[2]/w:r[4]/w:t'; + $this->assertEquals('Your name', $doc->getElement($path)->textContent); + + $path = '/w:document/w:body/w:p[3]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:checkBox")); + + $path = '/w:document/w:body/w:p[4]/w:r/w:fldChar/w:ffData/w:ddList'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('Choice 1', $doc->getElementAttribute("$path/w:listEntry[1]", 'w:val')); + $this->assertEquals('Choice 2', $doc->getElementAttribute("$path/w:listEntry[2]", 'w:val')); + $this->assertEquals('Choice 3', $doc->getElementAttribute("$path/w:listEntry[3]", 'w:val')); + $this->assertEquals('', trim($doc->getElementAttribute("$path/w:listEntry[4]", 'w:val'), ' ')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 6a295965..183ef553 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -249,33 +249,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase } } - /** - * Test shape elements - */ - public function testChartElements() - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - $style = array('width' => 1000000, 'height' => 1000000, 'showAxisLabels' => true, 'showGridX' => true, 'showGridY' => true); - - $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); - $categories = array('A', 'B', 'C', 'D', 'E'); - $series1 = array(1, 3, 2, 5, 4); - foreach ($chartTypes as $chartType) { - $section->addChart($chartType, $categories, $series1, $style); - } - $section->addChart('pie', $categories, $series1, array('3d' => true)); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $index = 0; - foreach ($chartTypes as $chartType) { - ++$index; - $file = "word/charts/chart{$index}.xml"; - $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; - $this->assertTrue($doc->elementExists($path, $file)); - } - } + // testChartElements moved to Writer/Word2007/Element/ChartTest public function testFieldElement() { @@ -354,27 +328,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase $this->assertEquals(' MACROBUTTON Zoom100 double click to zoom ', $doc->getElement($element)->textContent); } - /** - * Test form fields - */ - public function testFormFieldElements() - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - - $section->addFormField('textinput')->setName('MyTextBox'); - $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); - $section->addFormField('checkbox')->setDefault(true); - $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $path = '/w:document/w:body/w:p[%d]/w:r/w:fldChar/w:ffData'; - $this->assertTrue($doc->elementExists(sprintf($path, 1) . '/w:textInput')); - $this->assertTrue($doc->elementExists(sprintf($path, 2) . '/w:checkBox')); - $this->assertTrue($doc->elementExists(sprintf($path, 3) . '/w:checkBox')); - $this->assertTrue($doc->elementExists(sprintf($path, 4) . '/w:ddList')); - } + // testFormFieldElements moved to Writer/Word2007/Element/FormFieldTest /** * Test SDT elements diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 8a21e827..fcf5cabc 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -67,6 +67,8 @@ class SettingsTest extends \PHPUnit\Framework\TestCase $phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); + $sect = $phpWord->addSection(); + $sect->addText('This is a protected document'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -79,6 +81,31 @@ class SettingsTest extends \PHPUnit\Framework\TestCase $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); } + /** + * Test document protection with password without setting salt + */ + public function testDocumentProtectionWithPasswordNoSalt() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); + $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); + //$phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); + $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); + $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); + $sect = $phpWord->addSection(); + $sect->addText('This is a protected document'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:documentProtection'; + $this->assertTrue($doc->elementExists($path, $file)); + //$this->assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash')); + $this->assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid')); + $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); + } + /** * Test compatibility */ diff --git a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php index efa0a105..c2cbfcae 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php @@ -54,6 +54,42 @@ class ImageTest extends \PHPUnit\Framework\TestCase $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position'; + $this->assertFalse($doc->elementExists($path)); + $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; + $this->assertTrue($doc->elementExists($path . '/w10:wrap')); + $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); + + $this->assertTrue($doc->elementExists($path)); + $style = $doc->getElement($path)->getAttribute('style'); + $this->assertNotNull($style); + $this->assertContains('mso-wrap-distance-left:10pt;', $style); + $this->assertContains('mso-wrap-distance-right:20pt;', $style); + $this->assertContains('mso-wrap-distance-top:30pt;', $style); + $this->assertContains('mso-wrap-distance-bottom:40pt;', $style); + } + + /** + * Test writing image wrapping + */ + public function testWrappingWithPosition() + { + $styles = array( + 'wrap' => Image::WRAP_INLINE, + 'wrapDistanceLeft' => 10, + 'wrapDistanceRight' => 20, + 'wrapDistanceTop' => 30, + 'wrapDistanceBottom' => 40, + 'position' => 10, + ); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position'; + $this->assertEquals('10', $doc->getElement($path)->getAttribute('w:val')); $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; $this->assertTrue($doc->elementExists($path . '/w10:wrap')); $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); diff --git a/tests/PhpWord/Writer/Word2007/Style/SectionTest.php b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php new file mode 100644 index 00000000..74e1eadd --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php @@ -0,0 +1,57 @@ +addSection(); + $section->getStyle()->setMarginTop(0.1)->setMarginBottom(0.4)->setMarginLeft(0.2)->setMarginRight(0.3); + $section->addText('test'); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + Settings::setMeasurementUnit($unit); + + $path = '/w:document/w:body/w:sectPr/w:pgMar'; + $this->assertEquals('144', $doc->getElementAttribute($path, 'w:top')); + $this->assertEquals('432', $doc->getElementAttribute($path, 'w:right')); + $this->assertEquals('576', $doc->getElementAttribute($path, 'w:bottom')); + $this->assertEquals('288', $doc->getElementAttribute($path, 'w:left')); + } +} diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe..25fe836a 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,26 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 02fa7d78..d35f0e3f 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -63,7 +63,12 @@ class TestHelperDOCX $zip->close(); } - return new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + if ($writerName === 'ODText') { + $doc->setDefaultFile('content.xml'); + } + + return $doc; } /** diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bc..41a9d9db 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -50,6 +50,37 @@ class XmlDocument */ private $file; + /** + * Default file name + * + * @var string + */ + private $defaultFile = 'word/document.xml'; + + /** + * Get default file + * + * @return string + */ + public function getDefaultFile() + { + return $this->defaultFile; + } + + /** + * Set default file + * + * @param string $file + * @return string + */ + public function setDefaultFile($file) + { + $temp = $this->defaultFile; + $this->defaultFile = $file; + + return $temp; + } + /** * Create new instance * @@ -66,8 +97,11 @@ class XmlDocument * @param string $file * @return \DOMDocument */ - public function getFileDom($file = 'word/document.xml') + public function getFileDom($file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null !== $this->dom && $file === $this->file) { return $this->dom; } @@ -91,8 +125,11 @@ class XmlDocument * @param string $file * @return \DOMNodeList */ - public function getNodeList($path, $file = 'word/document.xml') + public function getNodeList($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null === $this->dom || $file !== $this->file) { $this->getFileDom($file); } @@ -112,8 +149,11 @@ class XmlDocument * @param string $file * @return \DOMElement */ - public function getElement($path, $file = 'word/document.xml') + public function getElement($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $elements = $this->getNodeList($path, $file); return $elements->item(0); @@ -147,8 +187,12 @@ class XmlDocument * @param string $file * @return string */ - public function getElementAttribute($path, $attribute, $file = 'word/document.xml') + public function getElementAttribute($path, $attribute, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } + return $this->getElement($path, $file)->getAttribute($attribute); } @@ -159,8 +203,11 @@ class XmlDocument * @param string $file * @return string */ - public function elementExists($path, $file = 'word/document.xml') + public function elementExists($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $nodeList = $this->getNodeList($path, $file); return $nodeList->length != 0; @@ -173,8 +220,11 @@ class XmlDocument * @param string $file * @return string */ - public function printXml($path = '/', $file = 'word/document.xml') + public function printXml($path = '/', $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $element = $this->getElement($path, $file); if ($element instanceof \DOMDocument) { $element->formatOutput = true; From d6260988bd6df5f20bf662f0467f6d1a10bea1cf Mon Sep 17 00:00:00 2001 From: Maxim Date: Thu, 23 Jul 2020 18:49:25 +0300 Subject: [PATCH 11/58] Allow to redefine TCPDF object Sometimes we need create TCPDF object with modified initial arguments. This change allow rewrite only createExternalWriterInstance() in user defined TCPDF class. --- src/PhpWord/Writer/PDF/TCPDF.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index badab046..2558c29e 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,6 +36,20 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; + /** + * Gets the implementation of external PDF library that should be used. + * + * @param string $orientation Page orientation + * @param string $unit Unit measure + * @param string $paperSize Paper size + * + * @return \TCPDF implementation + */ + protected function createExternalWriterInstance($orientation, $unit, $paperSize) + { + return new \TCPDF($orientation, $unit, $paperSize); + } + /** * Save PhpWord to file. * @@ -50,7 +64,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface $orientation = 'P'; // Create PDF - $pdf = new \TCPDF($orientation, 'pt', $paperSize); + $pdf = $this->createExternalWriterInstance($orientation, 'pt', $paperSize); $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); From 3a7dd774a2fa723a05b6c3345997f41f838a4b6c Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Tue, 1 Sep 2020 18:13:25 +0200 Subject: [PATCH 12/58] Add support for mc:AlternateContent --- .gitignore | 3 +++ src/PhpWord/Reader/Word2007/AbstractPart.php | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index dd858cea..da661ee3 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ phpword.ini /.project /nbproject /.php_cs.cache +docker-compose.yml +/phpdocker +/public diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 06dfe37b..17dbceb4 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -292,6 +292,19 @@ abstract class AbstractPart $parent->addTextBreak(); } elseif ($node->nodeName == 'w:tab') { $parent->addText("\t"); + } elseif ($node->nodeName == 'mc:AlternateContent') { + $hasChildren = $node->childNodes->length > 0; + + if ($hasChildren) { + $origin = $node->childNodes->item($node->childNodes->length - 1); + + if ($origin->nodeValue) { + // TextRun + $textContent = htmlspecialchars($origin->nodeValue, ENT_QUOTES, 'UTF-8'); + + $parent->addText($textContent, $fontStyle, $paragraphStyle); + } + } } elseif ($node->nodeName == 'w:t' || $node->nodeName == 'w:delText') { // TextRun $textContent = htmlspecialchars($xmlReader->getValue('.', $node), ENT_QUOTES, 'UTF-8'); From 63d1ffceb8f5aa627d706fc02d82b6ccd37a7691 Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Tue, 1 Sep 2020 18:14:27 +0200 Subject: [PATCH 13/58] Restore gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index da661ee3..dd858cea 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,3 @@ phpword.ini /.project /nbproject /.php_cs.cache -docker-compose.yml -/phpdocker -/public From 58e0200fbdb5634becb4c777f9624998935a38ff Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 12:12:48 +0200 Subject: [PATCH 14/58] Get fallback value instead of taking the last element --- src/PhpWord/Reader/Word2007/AbstractPart.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 17dbceb4..2bc71b3a 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -293,14 +293,14 @@ abstract class AbstractPart } elseif ($node->nodeName == 'w:tab') { $parent->addText("\t"); } elseif ($node->nodeName == 'mc:AlternateContent') { - $hasChildren = $node->childNodes->length > 0; - - if ($hasChildren) { - $origin = $node->childNodes->item($node->childNodes->length - 1); + if ($node->hasChildNodes()) { + // Get fallback instead of mc:Choice to make sure it is compatible + $fallbackElements = $node->getElementsByTagName('Fallback'); - if ($origin->nodeValue) { + if ($fallbackElements->length) { + $fallback = $fallbackElements->item(0); // TextRun - $textContent = htmlspecialchars($origin->nodeValue, ENT_QUOTES, 'UTF-8'); + $textContent = htmlspecialchars($fallback->nodeValue, ENT_QUOTES, 'UTF-8'); $parent->addText($textContent, $fontStyle, $paragraphStyle); } From ae34ae9518efc2bb6bdfc150e03b24fd72848702 Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 13:03:29 +0200 Subject: [PATCH 15/58] Add testcase --- composer.json | 2 +- tests/PhpWord/Reader/Word2007/ElementTest.php | 43 +++++++++++++++++++ .../PhpWord/_includes/AbstractTestReader.php | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f5f751ec..e8720b7b 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ ], "scripts": { "test": [ - "phpunit --color=always" + "phpunit --color=always --filter testReadAlternateContent" ], "test-no-coverage": [ "phpunit --color=always --no-coverage" diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index cb72ef9f..a0875a67 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -25,6 +25,49 @@ use PhpOffice\PhpWord\Element\TrackChange; */ class ElementTest extends AbstractTestReader { + /** + * Test reading of alternate content value + */ + public function testReadAlternateContent() + { + $documentXml = ' + + + + + + + + + + + + + + Test node value + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]->getElement(0)); + + $text = $elements[0]; + + $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); + } + /** * Test reading of textbreak */ diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php index d9097d71..12bd437a 100644 --- a/tests/PhpWord/_includes/AbstractTestReader.php +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -24,7 +24,7 @@ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase { private $parts = array( 'styles' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Styles', 'xml' => '{toReplace}'), - 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), + 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), 'footnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Footnotes', 'xml' => '{toReplace}'), 'endnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Endnotes', 'xml' => '{toReplace}'), 'settings' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Settings', 'xml' => '{toReplace}'), From 51034af207cd5f39636a541b7705e33edb09a69c Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 13:03:49 +0200 Subject: [PATCH 16/58] Remove filter option --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e8720b7b..f5f751ec 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ ], "scripts": { "test": [ - "phpunit --color=always --filter testReadAlternateContent" + "phpunit --color=always" ], "test-no-coverage": [ "phpunit --color=always --no-coverage" From 166a136f221b9d2c8dcfd0f740925492ce29d262 Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 14:36:08 +0200 Subject: [PATCH 17/58] Fix spacing --- tests/PhpWord/Reader/Word2007/ElementTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index a0875a67..d5db6be8 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -59,12 +59,9 @@ class ElementTest extends AbstractTestReader $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); $elements = $phpWord->getSection(0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]->getElement(0)); - $text = $elements[0]; - $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); } From adb917273c3f0504516a9e281ea61e6e97ed1382 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 12:56:06 +0200 Subject: [PATCH 18/58] allow PHP 7.4, 8.0 --- .travis.yml | 11 +++++++---- composer.json | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index acdf95cc..421e772c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,8 @@ php: - 7.1 - 7.2 - 7.3 - - 7.4snapshot + - 7.4 + - nightly matrix: include: @@ -26,14 +27,16 @@ matrix: env: COVERAGE=1 - php: 7.3 env: DEPENDENCIES="--ignore-platform-reqs" + - php: 7.4 + env: DEPENDENCIES="--ignore-platform-reqs" + - php: nightly + 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 + - php: nightly cache: directories: diff --git a/composer.json b/composer.json index f5f751ec..43738937 100644 --- a/composer.json +++ b/composer.json @@ -58,7 +58,7 @@ "fix": "Fixes issues found by PHP-CS" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", "phpoffice/common": "^0.2.9" @@ -67,13 +67,13 @@ "ext-zip": "*", "ext-gd": "*", "phpunit/phpunit": "^4.8.36 || ^7.0", - "squizlabs/php_codesniffer": "^2.9", + "squizlabs/php_codesniffer": "^2.9 || ^3.5", "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", - "phploc/phploc": "2.* || 3.* || 4.*", + "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.7.4 || 6.* || 7.*", + "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, "suggest": { From e334ecf059aa19b7ba82fa8600501efcb0b45ff4 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 13:39:22 +0200 Subject: [PATCH 19/58] compatibility with phpmd 2.9 --- phpmd.xml.dist | 2 ++ src/PhpWord/Reader/MsDoc.php | 16 ++++++++-------- tests/PhpWord/Element/TableTest.php | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 2077e02b..cfb9353b 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -5,6 +5,8 @@ xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> + + diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 1a9e4988..eb64e00a 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1581,7 +1581,7 @@ class MsDoc extends AbstractReader implements ReaderInterface // Variables $sprmCPicLocation = null; $sprmCFData = null; - $sprmCFSpec = null; + //$sprmCFSpec = null; do { // Variables @@ -1830,7 +1830,7 @@ class MsDoc extends AbstractReader implements ReaderInterface break; // sprmCFSpec case 0x55: - $sprmCFSpec = $operand; + //$sprmCFSpec = $operand; break; // sprmCFtcBi case 0x5E: @@ -2094,11 +2094,11 @@ class MsDoc extends AbstractReader implements ReaderInterface $sprmCPicLocation += 1; // stPicName - $stPicName = ''; + //$stPicName = ''; for ($inc = 0; $inc <= $cchPicName; $inc++) { - $chr = self::getInt1d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt1d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 1; - $stPicName .= chr($chr); + //$stPicName .= chr($chr); } } @@ -2143,11 +2143,11 @@ class MsDoc extends AbstractReader implements ReaderInterface $sprmCPicLocation += 1; // nameData if ($cbName > 0) { - $nameData = ''; + //$nameData = ''; for ($inc = 0; $inc <= ($cbName / 2); $inc++) { - $chr = self::getInt2d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt2d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 2; - $nameData .= chr($chr); + //$nameData .= chr($chr); } } // embeddedBlip diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 8ae5306c..17aa13a3 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -99,10 +99,10 @@ class TableTest extends \PHPUnit\Framework\TestCase { $oTable = new Table(); $oTable->addRow(); - $element = $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 1); - $element = $oTable->addCell(); - $element = $oTable->addCell(); + $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 3); } } From 9dad1d20e8ca3375fd7e8413ba3722232e758236 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 14:05:52 +0200 Subject: [PATCH 20/58] PHP 7.4 - fixed invalid value in hexdec avoid notice: "Invalid characters passed for attempted conversion, these have been ignored" --- src/PhpWord/Shared/Converter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 39e80545..05755ef7 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -338,9 +338,9 @@ class Converter return false; } - $red = hexdec($red); - $green = hexdec($green); - $blue = hexdec($blue); + $red = ctype_xdigit($red) ? hexdec($red) : 0; + $green = ctype_xdigit($green) ? hexdec($green) : 0; + $blue = ctype_xdigit($blue) ? hexdec($blue) : 0; return array($red, $green, $blue); } From 7fd4b64e8ad678d9017c08f89077344f2f024bee Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 14:26:19 +0200 Subject: [PATCH 21/58] - composer in php 5.x require increase memory limit - in PHP 7.3, 7.4 not necessary remove ignore platforms --- .travis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 421e772c..421df777 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,17 +18,12 @@ matrix: include: - 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" - - php: 7.4 - env: DEPENDENCIES="--ignore-platform-reqs" - php: nightly env: DEPENDENCIES="--ignore-platform-reqs" exclude: @@ -58,6 +53,8 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update + ## Composer in PHP versions 5.x requires 3 GB memory + - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) ## PHPDocumentor ##- mkdir -p build/docs From 93978211a13dbccd197e47090085a6565a6a2504 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 15:48:39 +0200 Subject: [PATCH 22/58] PHP 8.0 - depracated libxml_disable_entity_loader, is disabled by default --- src/PhpWord/Shared/Html.php | 8 ++++++-- src/PhpWord/TemplateProcessor.php | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 54e9509e..be1ef742 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -72,7 +72,9 @@ class Html } // Load DOM - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(true); + } $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); @@ -80,7 +82,9 @@ class Html $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } } /** diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1a..8aadb8c5 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -170,7 +170,9 @@ class TemplateProcessor */ protected function transformSingleXml($xml, $xsltProcessor) { - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $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,7 +182,9 @@ class TemplateProcessor if (false === $transformedXml) { throw new Exception('Could not transform the given XML document.'); } - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $transformedXml; } From 9c6cf6fdb622db07332d0c23f1ba47b123005670 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 15:56:40 +0200 Subject: [PATCH 23/58] PHP 8.0 fix - ValueError: file_exists(): Argument #1 ($filename) must not contain any null bytes --- src/PhpWord/Element/Image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bae87ff5..c6dd0e58 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ class Image extends AbstractElement } else { $this->sourceType = self::SOURCE_GD; } - } elseif (@file_exists($this->source)) { + } elseif (is_string($this->source) && @file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { From 93579e90efed9836d247c412715c1daf95906587 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 16:05:30 +0200 Subject: [PATCH 24/58] forgotten condition for libxml_disable_entity_loader --- tests/PhpWord/_includes/XmlDocument.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bc..14735511 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -76,10 +76,14 @@ class XmlDocument $this->file = $file; $file = $this->path . '/' . $file; - $orignalLibEntityLoader = libxml_disable_entity_loader(false); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(false); + } $this->dom = new \DOMDocument(); $this->dom->load($file); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $this->dom; } From a36a42912880d77fe6caabb0689b5c294fb3793d Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:08:23 +0200 Subject: [PATCH 25/58] rewrite check to local file --- src/PhpWord/Element/Image.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index c6dd0e58..081e3b5d 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ class Image extends AbstractElement } else { $this->sourceType = self::SOURCE_GD; } - } elseif (is_string($this->source) && @file_exists($this->source)) { + } elseif ($this->isFile($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { @@ -463,6 +463,18 @@ class Image extends AbstractElement } } + /** + * @param string $filename + * @return bool + */ + private function isFile($filename) { + try { + return @file_exists($filename); + } catch(\Exception $ex) { + return false; + } + } + /** * Get image size from archive * From bf1bb2b7ca5262312b17f8f7ebcb3f1121ff523d Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:17:46 +0200 Subject: [PATCH 26/58] PHP 8.0 - fixed Error: Unknown named parameter $styles --- 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 be1ef742..252665e7 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -182,7 +182,7 @@ class Html } } $method = "parse{$method}"; - $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments); + $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), array_values($arguments)); // Retrieve back variables from arguments foreach ($keys as $key) { From 2845284284260844169951689aa744646d1ca1c0 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:25:02 +0200 Subject: [PATCH 27/58] revert from develop branch --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 421df777..c7add667 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ matrix: - php: 5.3 - php: 5.4 - php: 5.5 + - php: 7.0 allow_failures: - php: nightly From 236c7c44998c64e7603574bbf084303a64a04ec9 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:34:51 +0200 Subject: [PATCH 28/58] fix code format --- src/PhpWord/Element/Image.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 081e3b5d..0662bd4c 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -467,10 +467,11 @@ class Image extends AbstractElement * @param string $filename * @return bool */ - private function isFile($filename) { + private function isFile($filename) + { try { return @file_exists($filename); - } catch(\Exception $ex) { + } catch (\Exception $ex) { return false; } } From 0edcab0da6a6075f6fee4e3bc0851c5cff08e885 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 07:26:06 +0200 Subject: [PATCH 29/58] allow php 5.3, 5.4, 5.5 except xenial os --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index c7add667..1b7b71da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,11 @@ matrix: env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 + dist: xenial - php: 5.4 + dist: xenial - php: 5.5 + dist: xenial - php: 7.0 allow_failures: - php: nightly From eaf2212aa8d2e5cc85757fb6f76428ab72748b5a Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 07:45:57 +0200 Subject: [PATCH 30/58] fix format for coverage --- .travis.yml | 1 - src/PhpWord/Element/AbstractContainer.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1b7b71da..05d21d82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,6 @@ matrix: dist: xenial - php: 5.5 dist: xenial - - php: 7.0 allow_failures: - php: nightly diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe..6a1ed930 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ abstract class AbstractContainer extends AbstractElement } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } From 6d49b28678466a63d09530b637e3ae4fdc96627b Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 07:47:25 +0200 Subject: [PATCH 31/58] skip TCPDF test in PHP 5.3, because version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, pending new release. --- tests/PhpWord/Writer/PDF/TCPDFTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 6dc8f24c..c8f5d222 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -33,6 +33,12 @@ class TCPDFTest extends \PHPUnit\Framework\TestCase */ public function testConstruct() { + // TCPDF version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, + // pending new release. + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + return; + } + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); From b7dc71ab1b64e0b42d0497c61d29f4732549a358 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 08:18:39 +0200 Subject: [PATCH 32/58] scrutinizer fix, allow zip extension --- .scrutinizer.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 2b395afd..d1fe5961 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,6 +3,12 @@ build: analysis: tests: override: [php-scrutinizer-run] + environment: + php: + version: '7.4' + pecl_extensions: + - zip + filter: excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] From b8ffe0477be771e9c09ce9edf28e6ea6b61bf13a Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 08:54:12 +0200 Subject: [PATCH 33/58] fix cs issue: "Arguments with default values must be at the end of the argument list" --- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 06dfe37b..eab659fa 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -573,11 +573,11 @@ abstract class AbstractPart * Returns the first child element found * * @param XMLReader $xmlReader - * @param \DOMElement $parentNode - * @param string|array $elements + * @param \DOMElement|null $parentNode + * @param string|array|null $elements * @return string|null */ - private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements) + private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements = null) { if (is_array($elements)) { //if element is an array, we take the first element that exists in the XML From 4e4282a76e7269f8e9586efd22f1364110e6e0d6 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 10:56:24 +0200 Subject: [PATCH 34/58] refixed "must not contain any null bytes" --- src/PhpWord/Element/Image.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 0662bd4c..2e25fd18 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ class Image extends AbstractElement } else { $this->sourceType = self::SOURCE_GD; } - } elseif ($this->isFile($this->source)) { + } elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { @@ -463,19 +463,6 @@ class Image extends AbstractElement } } - /** - * @param string $filename - * @return bool - */ - private function isFile($filename) - { - try { - return @file_exists($filename); - } catch (\Exception $ex) { - return false; - } - } - /** * Get image size from archive * From f2516b08b146da9b2be66326bb36d6f54fe56781 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 13:16:43 +0200 Subject: [PATCH 35/58] migrate from abandoned `Zend\Escaper` to `Laminas Escaper` --- README.md | 3 +-- composer.json | 5 ++++- docs/installing.rst | 4 +--- src/PhpWord/Writer/HTML/Element/AbstractElement.php | 4 ++-- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b15f83d7..30b008a2 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,7 @@ PHPWord requires the following: - PHP 5.3.3+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) -- [Zend\Escaper component](http://framework.zend.com/manual/current/en/modules/zend.escaper.introduction.html) -- [Zend\Stdlib component](http://framework.zend.com/manual/current/en/modules/zend.stdlib.hydrator.html) +- [Laminas Escaper component](https://docs.laminas.dev/laminas-escaper/intro/) - [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF) diff --git a/composer.json b/composer.json index 43738937..19997215 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ "require": { "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", - "zendframework/zend-escaper": "^2.2", + "laminas/laminas-escaper": "^2.2", "phpoffice/common": "^0.2.9" }, "require-dev": { @@ -76,6 +76,9 @@ "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, + "replace": { + "laminas/laminas-zendframework-bridge": "*" + }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", diff --git a/docs/installing.rst b/docs/installing.rst index 2a9582d0..baf966bd 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -10,9 +10,7 @@ Mandatory: - PHP 5.3.3+ - `XML Parser `__ extension -- `Zend\\Escaper `__ component -- Zend\\Stdlib component -- `Zend\\Validator `__ component +- `Laminas Escaper `__ component Optional: diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index dc5ccfaa..30d1ccaa 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * Abstract HTML element writer @@ -50,7 +50,7 @@ abstract class AbstractElement protected $withoutP = false; /** - * @var \Zend\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper + * @var \Laminas\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper */ protected $escaper; diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 2d86f399..97c76375 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * @since 0.11.0 @@ -32,7 +32,7 @@ abstract class AbstractPart private $parentWriter; /** - * @var \Zend\Escaper\Escaper + * @var \Laminas\Escaper\Escaper */ protected $escaper; From 4cc2cc1aeb54c29521fcc6e5a00e9016b4e604f3 Mon Sep 17 00:00:00 2001 From: Libor M Date: Mon, 19 Oct 2020 11:24:25 +0200 Subject: [PATCH 36/58] travis upgrade to PHPUnit 8 for PHP 8 --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 05d21d82..3c3e1819 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,6 +59,12 @@ before_script: ## Composer in PHP versions 5.x requires 3 GB memory - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) + ## PHP 8 require PHPUnit 8 + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + travis_wait composer remove phpunit/phpunit --dev --no-interaction --ignore-platform-reqs + travis_wait composer require phpunit/phpunit ^8.0 --dev --ignore-platform-reqs + fi ## PHPDocumentor ##- mkdir -p build/docs - mkdir -p build/coverage From 6b999233630eb99016906a46f34d77eb13ff1777 Mon Sep 17 00:00:00 2001 From: Libor M Date: Mon, 19 Oct 2020 14:44:28 +0200 Subject: [PATCH 37/58] travis php 8 - convert tests from phpunit 7 format to phpunit 8 format --- .travis.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3c3e1819..ef850687 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,11 +59,23 @@ before_script: ## Composer in PHP versions 5.x requires 3 GB memory - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) - ## PHP 8 require PHPUnit 8 + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) - | if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then travis_wait composer remove phpunit/phpunit --dev --no-interaction --ignore-platform-reqs travis_wait composer require phpunit/phpunit ^8.0 --dev --ignore-platform-reqs + + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; + + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; + + sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php + sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php fi ## PHPDocumentor ##- mkdir -p build/docs From ecc13ff62a87322f1f71f4a9b4dee76a1f98dc84 Mon Sep 17 00:00:00 2001 From: Nicholas Moore Date: Thu, 22 Oct 2020 13:53:28 +0300 Subject: [PATCH 38/58] Update templates-processing.rst fix typo in doc --- docs/templates-processing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 5bc11454..bac421c3 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -190,7 +190,7 @@ Finds a row in a table row identified by `$search` param and clones it as many t ['userId' => 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'], ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'], ]; - $templateProcessor->cloneRowAndSetValues('userId', ); + $templateProcessor->cloneRowAndSetValues('userId', $values); Will result in From a9e012530d9bdbdf426077917ff7974d2a6a5afb Mon Sep 17 00:00:00 2001 From: Libor M Date: Wed, 9 Dec 2020 13:03:49 +0100 Subject: [PATCH 39/58] travis support latest php as 8.0 now --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef850687..2d68941a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ php: - 7.2 - 7.3 - 7.4 - - nightly + - 8.0 matrix: include: @@ -24,7 +24,7 @@ matrix: dist: trusty - php: 7.0 env: COVERAGE=1 - - php: nightly + - php: 8.0 env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 @@ -34,7 +34,7 @@ matrix: - php: 5.5 dist: xenial allow_failures: - - php: nightly + - php: 8.0 cache: directories: From 4b4dfb4ccd392219a12579316e88fb477809e727 Mon Sep 17 00:00:00 2001 From: Libor M Date: Thu, 10 Dec 2020 15:27:31 +0100 Subject: [PATCH 40/58] update ugly hack for PHPUnit 8 support --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d68941a..aca5dbf8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,13 +58,17 @@ before_script: - composer self-update ## Composer in PHP versions 5.x requires 3 GB memory - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + travis_wait composer remove phpunit/phpunit --dev --no-update --no-interaction + travis_wait composer require phpunit/phpunit ^8.0 --dev --no-update + fi + ## Install composer packages - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) - | if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then - travis_wait composer remove phpunit/phpunit --dev --no-interaction --ignore-platform-reqs - travis_wait composer require phpunit/phpunit ^8.0 --dev --ignore-platform-reqs - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; From 36b63a107c51db41f1bf042c2365888dff338f89 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 11 Dec 2020 07:53:33 +0100 Subject: [PATCH 41/58] skip test, because php 8.0 contain internally validation --- tests/PhpWord/TemplateProcessorTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4caca77a..5b922f71 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -140,6 +140,11 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue() { + // Test is not needed for PHP 8.0, because internally validation throws TypeError exception. + if (\PHP_VERSION_ID >= 80000) { + $this->markTestSkipped('not needed for PHP 8.0'); + } + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); $xslDomDocument = new \DOMDocument(); From c8de86a7ec9e368e5e7cb48e03d51e20e979a6c0 Mon Sep 17 00:00:00 2001 From: SailorMax Date: Wed, 16 Dec 2020 17:24:42 +0300 Subject: [PATCH 42/58] allow to use customized pdf library --- src/PhpWord/Element/AbstractContainer.php | 1 + src/PhpWord/Writer/PDF/DomPDF.php | 12 +++++++++++- src/PhpWord/Writer/PDF/MPDF.php | 15 +++++++++++++-- src/PhpWord/Writer/PDF/TCPDF.php | 16 +++++++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe..6a1ed930 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ abstract class AbstractContainer extends AbstractElement } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 5fa8f75d..53eea815 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -35,6 +35,16 @@ class DomPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = null; + /** + * Gets the implementation of external PDF library that should be used. + * + * @return Dompdf implementation + */ + protected function createExternalWriterInstance() + { + return new DompdfLib(); + } + /** * Save PhpWord to file. * @@ -49,7 +59,7 @@ class DomPDF extends AbstractRenderer implements WriterInterface $orientation = 'portrait'; // Create PDF - $pdf = new DompdfLib(); + $pdf = $this->createExternalWriterInstance(); $pdf->setPaper(strtolower($paperSize), $orientation); $pdf->loadHtml(str_replace(PHP_EOL, '', $this->getContent())); $pdf->render(); diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index e63f5dfd..464f156c 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -44,6 +44,18 @@ class MPDF extends AbstractRenderer implements WriterInterface parent::__construct($phpWord); } + /** + * Gets the implementation of external PDF library that should be used. + * + * @return Mpdf implementation + */ + protected function createExternalWriterInstance() + { + $mPdfClass = $this->getMPdfClassName(); + + return new $mPdfClass(); + } + /** * Save PhpWord to file. * @@ -58,8 +70,7 @@ class MPDF extends AbstractRenderer implements WriterInterface $orientation = strtoupper('portrait'); // Create PDF - $mPdfClass = $this->getMPdfClassName(); - $pdf = new $mPdfClass(); + $pdf = $this->createExternalWriterInstance(); $pdf->_setPageSize($paperSize, $orientation); $pdf->addPage($orientation); diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index badab046..3abbbf06 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,6 +36,20 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; + /** + * Gets the implementation of external PDF library that should be used. + * + * @param string $orientation Page orientation + * @param string $unit Unit measure + * @param string $paperSize Paper size + * + * @return \TCPDF implementation + */ + protected function createExternalWriterInstance($orientation, $unit, $paperSize) + { + return new \TCPDF($orientation, $unit, $paperSize); + } + /** * Save PhpWord to file. * @@ -50,7 +64,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface $orientation = 'P'; // Create PDF - $pdf = new \TCPDF($orientation, 'pt', $paperSize); + $pdf = $this->createExternalWriterInstance($orientation, 'pt', $paperSize); $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); From 18e41a1c4e0a9afcc1317dffb35c48318a260b7e Mon Sep 17 00:00:00 2001 From: Ergashev Adizbek Date: Wed, 23 Dec 2020 16:00:06 +0500 Subject: [PATCH 43/58] Update TemplateProcessor.php --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1a..c8fc0b8a 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -575,7 +575,7 @@ class TemplateProcessor // define templates // result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425) - $imgTpl = ''; + $imgTpl = ''; foreach ($searchParts as $partFileName => &$partContent) { $partVariables = $this->getVariablesForPart($partContent); From 834a95c503361b8e15353e2ac98295561aea8d55 Mon Sep 17 00:00:00 2001 From: Antoine de Troostembergh Date: Wed, 30 Dec 2020 20:29:43 +0100 Subject: [PATCH 44/58] fix formatting --- src/PhpWord/Writer/PDF/TCPDF.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index f31ca1b1..9cd01ffd 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,7 +36,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; - /** + /** * Gets the implementation of external PDF library that should be used. * * @param string $orientation Page orientation From cf808cb3fcc436f344eef5b4b3e60b75e515d240 Mon Sep 17 00:00:00 2001 From: Antoine de Troostembergh Date: Thu, 31 Dec 2020 21:56:45 +0100 Subject: [PATCH 45/58] Fix merge issue --- src/PhpWord/Writer/PDF/TCPDF.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 9cd01ffd..3abbbf06 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -50,20 +50,6 @@ class TCPDF extends AbstractRenderer implements WriterInterface return new \TCPDF($orientation, $unit, $paperSize); } - /** - * Gets the implementation of external PDF library that should be used. - * - * @param string $orientation Page orientation - * @param string $unit Unit measure - * @param string $paperSize Paper size - * - * @return \TCPDF implementation - */ - protected function createExternalWriterInstance($orientation, $unit, $paperSize) - { - return new \TCPDF($orientation, $unit, $paperSize); - } - /** * Save PhpWord to file. * From c52686c2436eed853ec2a993811a12c3d5829dd8 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:09:16 +0100 Subject: [PATCH 46/58] \PhpOffice\Common\Text -> \PhpOffice\PhpWord\Shared\Text --- src/PhpWord/Element/Bookmark.php | 4 +- src/PhpWord/Element/CheckBox.php | 4 +- src/PhpWord/Element/Link.php | 6 +- src/PhpWord/Element/ListItem.php | 4 +- src/PhpWord/Element/PreserveText.php | 4 +- src/PhpWord/Element/Text.php | 4 +- src/PhpWord/Element/Title.php | 4 +- src/PhpWord/Shared/Text.php | 235 ++++++++++++++++++ src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- .../Writer/RTF/Element/AbstractElement.php | 4 +- .../Word2007/Element/AbstractElement.php | 4 +- tests/PhpWord/Shared/TextTest.php | 88 +++++++ 14 files changed, 345 insertions(+), 22 deletions(-) create mode 100644 src/PhpWord/Shared/Text.php create mode 100644 tests/PhpWord/Shared/TextTest.php diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 16b020d7..856f6860 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Bookmark element @@ -45,7 +45,7 @@ class Bookmark extends AbstractElement */ public function __construct($name = '') { - $this->name = CommonText::toUTF8($name); + $this->name = SharedText::toUTF8($name); } /** diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index f3e87176..beabf8a0 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Check box element @@ -55,7 +55,7 @@ class CheckBox extends Text */ public function setName($name) { - $this->name = CommonText::toUTF8($name); + $this->name = SharedText::toUTF8($name); return $this; } diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 2bec32dd..25a87fee 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -79,8 +79,8 @@ class Link extends AbstractElement */ public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false) { - $this->source = CommonText::toUTF8($source); - $this->text = is_null($text) ? $this->source : CommonText::toUTF8($text); + $this->source = SharedText::toUTF8($source); + $this->text = is_null($text) ? $this->source : SharedText::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->internal = $internal; diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 8b064c47..40381de0 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** @@ -57,7 +57,7 @@ class ListItem extends AbstractElement */ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->textObject = new Text(CommonText::toUTF8($text), $fontStyle, $paragraphStyle); + $this->textObject = new Text(SharedText::toUTF8($text), $fontStyle, $paragraphStyle); $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 374f1a99..c0e64268 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -59,7 +59,7 @@ class PreserveText extends AbstractElement $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index f4d7f081..1ad497b0 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -136,7 +136,7 @@ class Text extends AbstractElement */ public function setText($text) { - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); return $this; } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index d01f7f33..f061b3d5 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; /** @@ -62,7 +62,7 @@ class Title extends AbstractElement public function __construct($text, $depth = 1) { if (is_string($text)) { - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); } elseif ($text instanceof TextRun) { $this->text = $text; } else { diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php new file mode 100644 index 00000000..b9bea3ad --- /dev/null +++ b/src/PhpWord/Shared/Text.php @@ -0,0 +1,235 @@ +) + * element or in the shared string element. + * + * @param string $value Value to escape + * @return string + */ + public static function controlCharacterPHP2OOXML($value = '') + { + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); + } + + return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value); + } + + /** + * Return a number formatted for being integrated in xml files + * @param float $number + * @param integer $decimals + * @return string + */ + public static function numberFormat($number, $decimals) + { + return number_format($number, $decimals, '.', ''); + } + + /** + * @param int $dec + * @link http://stackoverflow.com/a/7153133/2235790 + * @author velcrow + * @return string + */ + public static function chr($dec) + { + if ($dec<=0x7F) { + return chr($dec); + } + if ($dec<=0x7FF) { + return chr(($dec>>6)+192).chr(($dec&63)+128); + } + if ($dec<=0xFFFF) { + return chr(($dec>>12)+224).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + } + if ($dec<=0x1FFFFF) { + return chr(($dec>>18)+240).chr((($dec>>12)&63)+128).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + } + return ''; + } + + /** + * Convert from OpenXML escaped control character to PHP control character + * + * @param string $value Value to unescape + * @return string + */ + public static function controlCharacterOOXML2PHP($value = '') + { + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); + } + + return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value); + } + + /** + * Check if a string contains UTF-8 data + * + * @param string $value + * @return boolean + */ + public static function isUTF8($value = '') + { + return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1); + } + + /** + * Return UTF8 encoded value + * + * @param string $value + * @return string + */ + public static function toUTF8($value = '') + { + if (!is_null($value) && !self::isUTF8($value)) { + $value = utf8_encode($value); + } + + return $value; + } + + /** + * Returns unicode from UTF8 text + * + * The function is splitted to reduce cyclomatic complexity + * + * @param string $text UTF8 text + * @return string Unicode text + * @since 0.11.0 + */ + public static function toUnicode($text) + { + return self::unicodeToEntities(self::utf8ToUnicode($text)); + } + + /** + * Returns unicode array from UTF8 text + * + * @param string $text UTF8 text + * @return array + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + public static function utf8ToUnicode($text) + { + $unicode = array(); + $values = array(); + $lookingFor = 1; + + // Gets unicode for each character + for ($i = 0; $i < strlen($text); $i++) { + $thisValue = ord($text[$i]); + if ($thisValue < 128) { + $unicode[] = $thisValue; + } else { + if (count($values) == 0) { + $lookingFor = $thisValue < 224 ? 2 : 3; + } + $values[] = $thisValue; + if (count($values) == $lookingFor) { + if ($lookingFor == 3) { + $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64); + } else { + $number = (($values[0] % 32) * 64) + ($values[1] % 64); + } + $unicode[] = $number; + $values = array(); + $lookingFor = 1; + } + } + } + + return $unicode; + } + + /** + * Returns entites from unicode array + * + * @param array $unicode + * @return string + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + private static function unicodeToEntities($unicode) + { + $entities = ''; + + foreach ($unicode as $value) { + if ($value != 65279) { + $entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value); + } + } + + return $entities; + } + + /** + * Return name without underscore for < 0.10.0 variable name compatibility + * + * @param string $value + * @return string + */ + public static function removeUnderscorePrefix($value) + { + if (!is_null($value)) { + if (substr($value, 0, 1) == '_') { + $value = substr($value, 1); + } + } + + return $value; + } +} diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 8edbe80b..aca6635f 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\Common\Text; +use PhpOffice\PhpWord\Shared\Text; /** * Abstract style class diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 580ef54a..522dea9b 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\TextAlignment; diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 08d328b1..7806530b 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,13 +17,13 @@ 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; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\Shared\ZipArchive; class TemplateProcessor diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 132890e6..fa1058bd 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; -use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Escaper\Rtf; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -126,7 +126,7 @@ abstract class AbstractElement extends HTMLAbstractElement return $this->escaper->escape($text); } - return CommonText::toUnicode($text); // todo: replace with `return $text;` later. + return SharedText::toUnicode($text); // todo: replace with `return $text;` later. } /** diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 63f45a76..6f83df67 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\Text as CommonText; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Abstract element writer @@ -207,7 +207,7 @@ abstract class AbstractElement */ protected function getText($text) { - return CommonText::controlCharacterPHP2OOXML($text); + return SharedText::controlCharacterPHP2OOXML($text); } /** diff --git a/tests/PhpWord/Shared/TextTest.php b/tests/PhpWord/Shared/TextTest.php new file mode 100644 index 00000000..ded00e96 --- /dev/null +++ b/tests/PhpWord/Shared/TextTest.php @@ -0,0 +1,88 @@ +assertEquals('', Text::controlCharacterPHP2OOXML()); + $this->assertEquals('aeiou', Text::controlCharacterPHP2OOXML('aeiou')); + $this->assertEquals('àéîöù', Text::controlCharacterPHP2OOXML('àéîöù')); + + $value = rand(0, 8); + $this->assertEquals('_x'.sprintf('%04s', strtoupper(dechex($value))).'_', Text::controlCharacterPHP2OOXML(chr($value))); + + $this->assertEquals('', Text::controlCharacterOOXML2PHP('')); + $this->assertEquals(chr(0x08), Text::controlCharacterOOXML2PHP('_x0008_')); + } + + public function testNumberFormat() + { + $this->assertEquals('2.1', Text::numberFormat('2.06', 1)); + $this->assertEquals('2.1', Text::numberFormat('2.12', 1)); + $this->assertEquals('1234.0', Text::numberFormat(1234, 1)); + } + + public function testChr() + { + $this->assertEquals('A', Text::chr(65)); + $this->assertEquals('A', Text::chr(0x41)); + $this->assertEquals('é', Text::chr(233)); + $this->assertEquals('é', Text::chr(0xE9)); + $this->assertEquals('⼳', Text::chr(12083)); + $this->assertEquals('⼳', Text::chr(0x2F33)); + $this->assertEquals('🌃', Text::chr(127747)); + $this->assertEquals('🌃', Text::chr(0x1F303)); + $this->assertEquals('', Text::chr(2097152)); + } + /** + * Is UTF8 + */ + public function testIsUTF8() + { + $this->assertTrue(Text::isUTF8('')); + $this->assertTrue(Text::isUTF8('éééé')); + $this->assertFalse(Text::isUTF8(utf8_decode('éééé'))); + } + + /** + * Test unicode conversion + */ + public function testToUnicode() + { + $this->assertEquals('a', Text::toUnicode('a')); + $this->assertEquals('\uc0{\u8364}', Text::toUnicode('€')); + $this->assertEquals('\uc0{\u233}', Text::toUnicode('é')); + } + + /** + * Test remove underscore prefix + */ + public function testRemoveUnderscorePrefix() + { + $this->assertEquals('item', Text::removeUnderscorePrefix('_item')); + } +} From b656720619768c5a423b7e26a1c0423b74c6ef4d Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:15:24 +0100 Subject: [PATCH 47/58] \PhpOffice\Common\Drawing -> \PhpOffice\PhpWord\Shared\Drawing --- src/PhpWord/Reader/MsDoc.php | 2 +- src/PhpWord/Shared/Drawing.php | 238 +++++++++++++++++++++++++++ tests/PhpWord/Shared/DrawingTest.php | 124 ++++++++++++++ 3 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/Shared/Drawing.php create mode 100644 tests/PhpWord/Shared/DrawingTest.php diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index eb64e00a..b4c194ca 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Shared\OLERead; use PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php new file mode 100644 index 00000000..25110582 --- /dev/null +++ b/src/PhpWord/Shared/Drawing.php @@ -0,0 +1,238 @@ +assertEquals(0, Drawing::degreesToAngle()); + $this->assertEquals((int) round($value * 60000), Drawing::degreesToAngle($value)); + $this->assertEquals(0, Drawing::angleToDegrees()); + $this->assertEquals(round($value / 60000), Drawing::angleToDegrees($value)); + } + + /** + */ + public function testPixelsCentimeters() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToCentimeters()); + $this->assertEquals($value / Drawing::DPI_96 * 2.54, Drawing::pixelsToCentimeters($value)); + $this->assertEquals(0, Drawing::centimetersToPixels()); + $this->assertEquals($value / 2.54 * Drawing::DPI_96, Drawing::centimetersToPixels($value)); + } + + /** + */ + public function testPixelsEMU() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToEmu()); + $this->assertEquals(round($value*9525), Drawing::pixelsToEmu($value)); + $this->assertEquals(0, Drawing::emuToPixels()); + $this->assertEquals(round($value/9525), Drawing::emuToPixels($value)); + } + + /** + */ + public function testPixelsPoints() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToPoints()); + $this->assertEquals($value*0.67777777, Drawing::pixelsToPoints($value)); + $this->assertEquals(0, Drawing::pointsToPixels()); + $this->assertEquals($value* 1.333333333, Drawing::pointsToPixels($value)); + } + + /** + */ + public function testPointsCentimeters() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pointsToCentimeters()); + $this->assertEquals($value * 1.333333333 / Drawing::DPI_96 * 2.54, Drawing::pointsToCentimeters($value)); + } + + /** + */ + public function testTwips() + { + $value = rand(1, 100); + + // Centimeters + $this->assertEquals(0, Drawing::centimetersToTwips()); + $this->assertEquals($value * 566.928, Drawing::centimetersToTwips($value)); + + $this->assertEquals(0, Drawing::twipsToCentimeters()); + $this->assertEquals($value / 566.928, Drawing::twipsToCentimeters($value)); + + // Inches + $this->assertEquals(0, Drawing::inchesToTwips()); + $this->assertEquals($value * 1440, Drawing::inchesToTwips($value)); + + $this->assertEquals(0, Drawing::twipsToInches()); + $this->assertEquals($value / 1440, Drawing::twipsToInches($value)); + + // Pixels + $this->assertEquals(0, Drawing::twipsToPixels()); + $this->assertEquals(round($value / 15.873984), Drawing::twipsToPixels($value)); + } + + public function testHTML() + { + $this->assertFalse(Drawing::htmlToRGB('0')); + $this->assertFalse(Drawing::htmlToRGB('00')); + $this->assertFalse(Drawing::htmlToRGB('0000')); + $this->assertFalse(Drawing::htmlToRGB('00000')); + + $this->assertInternalType('array', Drawing::htmlToRGB('ABCDEF')); + $this->assertCount(3, Drawing::htmlToRGB('ABCDEF')); + $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('ABCDEF')); + $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('#ABCDEF')); + $this->assertEquals(array(0xAA, 0xBB, 0xCC), Drawing::htmlToRGB('ABC')); + $this->assertEquals(array(0xAA, 0xBB, 0xCC), Drawing::htmlToRGB('#ABC')); + } +} From 9a26ad9189f9cf29aad5e429f62fdff81aa1dd30 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:23:58 +0100 Subject: [PATCH 48/58] \PhpOffice\Common\Microsoft\PasswordEncoder -> \PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder --- src/PhpWord/Metadata/Protection.php | 2 +- .../Shared/Microsoft/PasswordEncoder.php | 235 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- .../Shared/Microsoft/PasswordEncoderTest.php | 88 +++++++ 4 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 src/PhpWord/Shared/Microsoft/PasswordEncoder.php create mode 100644 tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 15aa3ff1..a46d43b9 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Metadata; -use PhpOffice\Common\Microsoft\PasswordEncoder; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\DocProtect; /** diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php new file mode 100644 index 00000000..fc0c7ecd --- /dev/null +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -0,0 +1,235 @@ + array(1, 'md2'), + self::ALGORITHM_MD4 => array(2, 'md4'), + self::ALGORITHM_MD5 => array(3, 'md5'), + self::ALGORITHM_SHA_1 => array(4, 'sha1'), + self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() + self::ALGORITHM_RIPEMD => array(6, 'ripemd'), + self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), + self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() + self::ALGORITHM_SHA_256 => array(12, 'sha256'), + self::ALGORITHM_SHA_384 => array(13, 'sha384'), + self::ALGORITHM_SHA_512 => array(14, 'sha512'), + ); + + private static $initialCodeArray = array( + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3, + ); + + private static $encryptionMatrix = array( + array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09), + array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF), + array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0), + array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40), + array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5), + array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A), + array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9), + array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0), + array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC), + array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10), + array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168), + array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C), + array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD), + array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC), + array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4), + ); + + private static $passwordMaxLength = 15; + + /** + * Create a hashed password that MS Word will be able to work with + * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ + * + * @param string $password + * @param string $algorithmName + * @param string $salt + * @param int $spinCount + * @return string + */ + public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) + { + $origEncoding = mb_internal_encoding(); + mb_internal_encoding('UTF-8'); + + $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); + + // Get the single-byte values by iterating through the Unicode characters of the truncated password. + // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. + $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); + $byteChars = array(); + + for ($i = 0; $i < mb_strlen($password); $i++) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); + + if ($byteChars[$i] == 0) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1)); + } + } + + // build low-order word and hig-order word and combine them + $combinedKey = self::buildCombinedKey($byteChars); + // build reversed hexadecimal string + $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); + $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; + + $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); + + // Implementation Notes List: + // Word requires that the initial hash of the password with the salt not be considered in the count. + // The initial hash of salt + key is not included in the iteration count. + $algorithm = self::getAlgorithm($algorithmName); + $generatedKey = hash($algorithm, $salt . $generatedKey, true); + + for ($i = 0; $i < $spinCount; $i++) { + $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true); + } + $generatedKey = base64_encode($generatedKey); + + mb_internal_encoding($origEncoding); + + return $generatedKey; + } + + /** + * Get algorithm from self::$algorithmMapping + * + * @param string $algorithmName + * @return string + */ + private static function getAlgorithm($algorithmName) + { + $algorithm = self::$algorithmMapping[$algorithmName][1]; + if ($algorithm == '') { + $algorithm = 'sha1'; + } + + return $algorithm; + } + + /** + * Returns the algorithm ID + * + * @param string $algorithmName + * @return int + */ + public static function getAlgorithmId($algorithmName) + { + return self::$algorithmMapping[$algorithmName][0]; + } + + /** + * Build combined key from low-order word and high-order word + * + * @param array $byteChars byte array representation of password + * @return int + */ + private static function buildCombinedKey($byteChars) + { + $byteCharsLength = count($byteChars); + // Compute the high-order word + // Initialize from the initial code array (see above), depending on the passwords length. + $highOrderWord = self::$initialCodeArray[$byteCharsLength - 1]; + + // For each character in the password: + // For every bit in the character, starting with the least significant and progressing to (but excluding) + // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from + // the Encryption Matrix + for ($i = 0; $i < $byteCharsLength; $i++) { + $tmp = self::$passwordMaxLength - $byteCharsLength + $i; + $matrixRow = self::$encryptionMatrix[$tmp]; + for ($intBit = 0; $intBit < 7; $intBit++) { + if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { + $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); + } + } + } + + // Compute low-order word + // Initialize with 0 + $lowOrderWord = 0; + // For each character in the password, going backwards + for ($i = $byteCharsLength - 1; $i >= 0; $i--) { + // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); + } + // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B); + + // Combine the Low and High Order Word + return self::int32(($highOrderWord << 16) + $lowOrderWord); + } + + /** + * Simulate behaviour of (signed) int32 + * + * @codeCoverageIgnore + * @param int $value + * @return int + */ + private static function int32($value) + { + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) { + $value = -((~$value & 0xFFFFFFFF) + 1); + } + + return $value; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index b764642a..42d3a5d5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\Style\Language; /** diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php new file mode 100644 index 00000000..47fb5481 --- /dev/null +++ b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php @@ -0,0 +1,88 @@ +assertEquals('M795/MAlmGU8RIsY9Q9uDLHC7bk=', $hashPassword); + } + + /** + * Test that a password can be hashed with a custom salt + */ + public function testEncodePasswordWithSalt() + { + //given + $password = 'test'; + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_SHA_1, $salt); + + //then + $this->assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); + } + + /** + * Test that the encoder falls back on SHA-1 if a non supported algorithm is given + */ + public function testDefaultsToSha1IfUnsupportedAlgorithm() + { + //given + $password = 'test'; + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt); + + //then + $this->assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); + } + + /** + * Test that the encoder falls back on SHA-1 if a non supported algorithm is given + */ + public function testEncodePasswordWithNullAsciiCodeInPassword() + { + //given + $password = 'test' . chr(0); + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt, 1); + + //then + $this->assertEquals('rDV9sgdDsztoCQlvRCb1lF2wxNg=', $hashPassword); + } +} From 0cca050bcd21f161062410f4f7fca0faa072755f Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:33:27 +0100 Subject: [PATCH 49/58] \PhpOffice\Common\XMLReader -> \PhpOffice\PhpWord\Shared\XMLReader --- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 22 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- .../Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 8 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 4 +- src/PhpWord/Reader/Word2007/Settings.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Shared/XMLReader.php | 211 ++++++++++++++++++ tests/PhpWord/Shared/XMLReaderTest.php | 134 +++++++++++ tests/PhpWord/_files/xml/reader.zip | Bin 0 -> 272 bytes 15 files changed, 371 insertions(+), 26 deletions(-) create mode 100644 src/PhpWord/Shared/XMLReader.php create mode 100644 tests/PhpWord/Shared/XMLReaderTest.php create mode 100644 tests/PhpWord/_files/xml/reader.zip diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 0b58dc50..d0aa9138 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Reader for ODText diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 9dfd6453..cec06418 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\ODText; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Content reader diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 8801a543..9a3d8341 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\ODText; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Meta reader diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 52030ef8..699a4ead 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Shared\ZipArchive; /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index eab659fa..083161d0 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -17,12 +17,12 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Abstract part reader @@ -95,7 +95,7 @@ abstract class AbstractPart /** * Read w:p. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart @@ -202,7 +202,7 @@ abstract class AbstractPart /** * Read w:r. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart @@ -320,7 +320,7 @@ abstract class AbstractPart /** * Read w:tbl. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart @@ -378,7 +378,7 @@ abstract class AbstractPart /** * Read w:pPr. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -413,7 +413,7 @@ abstract class AbstractPart /** * Read w:rPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -459,7 +459,7 @@ abstract class AbstractPart /** * Read w:tblPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" @@ -509,7 +509,7 @@ abstract class AbstractPart /** * Read w:tblpPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -534,7 +534,7 @@ abstract class AbstractPart /** * Read w:tblInd * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return TblWidthComplexType */ @@ -552,7 +552,7 @@ abstract class AbstractPart /** * Read w:tcPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -620,7 +620,7 @@ abstract class AbstractPart /** * Read style definition * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $parentNode * @param array $styleDefs * @ignoreScrutinizerPatch diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 36eecebe..d241df18 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Core properties reader diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index a6835aac..feb41006 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Custom properties reader diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index f0d1194a..13a92e47 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Document reader @@ -97,7 +97,7 @@ class Document extends AbstractPart /** * Read w:sectPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @ignoreScrutinizerPatch * @return array @@ -141,7 +141,7 @@ class Document extends AbstractPart /** * Read w:p node. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section * @@ -170,7 +170,7 @@ class Document extends AbstractPart /** * Read w:sectPr node. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 634f4739..a8829d0b 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Footnotes reader diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 3f57cbf8..dea8f3ee 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Numbering reader @@ -89,7 +89,7 @@ class Numbering extends AbstractPart /** * Read numbering level definition from w:abstractNum and w:num * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $subnode * @param int $levelId * @return array diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 3084943b..0a59e045 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 97f29b43..37ce4909 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php new file mode 100644 index 00000000..77013f6c --- /dev/null +++ b/src/PhpWord/Shared/XMLReader.php @@ -0,0 +1,211 @@ +open($zipFile); + $content = $zip->getFromName($xmlFile); + $zip->close(); + + if ($content === false) { + return false; + } + + return $this->getDomFromString($content); + } + + /** + * Get DOMDocument from content string + * + * @param string $content + * @return \DOMDocument + */ + public function getDomFromString($content) + { + $originalLibXMLEntityValue = libxml_disable_entity_loader(true); + $this->dom = new \DOMDocument(); + $this->dom->loadXML($content); + libxml_disable_entity_loader($originalLibXMLEntityValue); + + return $this->dom; + } + + /** + * Get elements + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMNodeList + */ + public function getElements($path, \DOMElement $contextNode = null) + { + if ($this->dom === null) { + return array(); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + + if (is_null($contextNode)) { + return $this->xpath->query($path); + } + + return $this->xpath->query($path, $contextNode); + } + + /** + * Registers the namespace with the DOMXPath object + * + * @param string $prefix The prefix + * @param string $namespaceURI The URI of the namespace + * @return bool true on success or false on failure + * @throws \InvalidArgumentException If called before having loaded the DOM document + */ + public function registerNamespace($prefix, $namespaceURI) + { + if ($this->dom === null) { + throw new \InvalidArgumentException('Dom needs to be loaded before registering a namespace'); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + return $this->xpath->registerNamespace($prefix, $namespaceURI); + } + + /** + * Get element + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMElement|null + */ + public function getElement($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0); + } + + return null; + } + + /** + * Get element attribute + * + * @param string $attribute + * @param \DOMElement $contextNode + * @param string $path + * @return string|null + */ + public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) + { + $return = null; + if ($path !== null) { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + /** @var \DOMElement $node Type hint */ + $node = $elements->item(0); + $return = $node->getAttribute($attribute); + } + } else { + if ($contextNode !== null) { + $return = $contextNode->getAttribute($attribute); + } + } + + return ($return == '') ? null : $return; + } + + /** + * Get element value + * + * @param string $path + * @param \DOMElement $contextNode + * @return string|null + */ + public function getValue($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0)->nodeValue; + } + + return null; + } + + /** + * Count elements + * + * @param string $path + * @param \DOMElement $contextNode + * @return integer + */ + public function countElements($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + + return $elements->length; + } + + /** + * Element exists + * + * @param string $path + * @param \DOMElement $contextNode + * @return boolean + */ + public function elementExists($path, \DOMElement $contextNode = null) + { + return $this->getElements($path, $contextNode)->length > 0; + } +} diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php new file mode 100644 index 00000000..a34d650a --- /dev/null +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -0,0 +1,134 @@ +getDomFromString('AAA'); + + $this->assertTrue($reader->elementExists('/element/child')); + $this->assertEquals('AAA', $reader->getElement('/element/child')->textContent); + $this->assertEquals('AAA', $reader->getValue('/element/child')); + $this->assertEquals('test', $reader->getAttribute('attr', $reader->getElement('/element'))); + $this->assertEquals('subtest', $reader->getAttribute('attr', $reader->getElement('/element'), 'child')); + } + + /** + * Test reading XML from zip + */ + public function testDomFromZip() + { + $archiveFile = __DIR__ . '/../_files/xml/reader.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, 'test.xml'); + + $this->assertTrue($reader->elementExists('/element/child')); + + $this->assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml')); + } + + /** + * Test that read from non existing archive throws exception + * + * @expectedException Exception + */ + public function testThrowsExceptionOnNonExistingArchive() + { + $archiveFile = __DIR__ . '/../_files/xml/readers.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, 'test.xml'); + } + + /** + * Test elements count + */ + public function testCountElements() + { + $reader = new XMLReader(); + $reader->getDomFromString('AAABBB'); + + $this->assertEquals(2, $reader->countElements('/element/child')); + } + + /** + * Test read non existing elements + */ + public function testReturnNullOnNonExistingNode() + { + $reader = new XMLReader(); + $this->assertEmpty($reader->getElements('/element/children')); + $reader->getDomFromString('AAA'); + + $this->assertNull($reader->getElement('/element/children')); + $this->assertNull($reader->getValue('/element/children')); + } + + /** + * Test that xpath fails if custom namespace is not registered + */ + public function testShouldThrowExceptionIfNamespaceIsNotKnown() + { + try { + $reader = new XMLReader(); + $reader->getDomFromString('AAA'); + + $this->assertTrue($reader->elementExists('/element/test:child')); + $this->assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); + $this->fail(); + } catch (\Exception $e) { + $this->assertTrue(true); + } + } + + /** + * Test reading XML with manually registered namespace + */ + public function testShouldParseXmlWithCustomNamespace() + { + $reader = new XMLReader(); + $reader->getDomFromString('AAA'); + $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); + + $this->assertTrue($reader->elementExists('/element/test:child')); + $this->assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); + } + + /** + * Test that xpath fails if custom namespace is not registered + * + * @expectedException InvalidArgumentException + */ + public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc() + { + $reader = new XMLReader(); + $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); + } +} diff --git a/tests/PhpWord/_files/xml/reader.zip b/tests/PhpWord/_files/xml/reader.zip new file mode 100644 index 0000000000000000000000000000000000000000..dbe69cbbc03f9ab229f52b6ccdce012abfa8fae5 GIT binary patch literal 272 zcmWIWW@Zs#U|`^2*i|{f`-6HZV-}Ft1{RTFC`m0Y(W}VK2@T<7U{=sFjZy^S(h6<{ zMwYLP3=CkMu4f#%nhgXTE|zldb)K>J*1H%Vo|C>!GjBP}X^?cyU!S13`+Rhb$?rK= z+`Kzyn%3Mh*LY;ueqwT4=ssWmRUOYC1gBjp2w*hcGtZ+lEh#WA<)T6ei(cJ>AKjWf z*P`CMTk~Sh>W;hr3%+s&cr!A|G2?Qr1klY43_w>gENKL>5N>CMxE;;i0p6@^Aa#sD L=m(_NfH({Qga}Y@ literal 0 HcmV?d00001 From 357e905e8b897b0b5b521a8de50a97093106d5e3 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:52:15 +0100 Subject: [PATCH 50/58] fix PasswordEncoder namespace --- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index fcf5cabc..d3c1c1dd 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; From a2c8d8c2d50a5ac35f6fa792b833f7f4e01f7267 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 08:26:46 +0100 Subject: [PATCH 51/58] \PhpOffice\Common\XMLWriter -> \PhpOffice\PhpWord\Shared\XMLWriter --- src/PhpWord/Shared/XMLWriter.php | 184 ++++++++++++++++++ src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 6 +- .../Writer/ODText/Part/AbstractPart.php | 6 +- src/PhpWord/Writer/ODText/Part/Content.php | 6 +- src/PhpWord/Writer/ODText/Part/Meta.php | 4 +- src/PhpWord/Writer/ODText/Part/Styles.php | 12 +- .../Word2007/Element/AbstractElement.php | 8 +- .../Writer/Word2007/Element/Container.php | 4 +- .../Writer/Word2007/Element/FormField.php | 8 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 10 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 12 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 8 +- src/PhpWord/Writer/Word2007/Element/Table.php | 8 +- .../Writer/Word2007/Part/AbstractPart.php | 4 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 14 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 4 +- .../Writer/Word2007/Part/ContentTypes.php | 4 +- src/PhpWord/Writer/Word2007/Part/Document.php | 6 +- .../Writer/Word2007/Part/Footnotes.php | 4 +- .../Writer/Word2007/Part/Numbering.php | 8 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 8 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 10 +- .../Writer/Word2007/Style/AbstractStyle.php | 10 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 4 +- .../Writer/Word2007/Style/MarginBorder.php | 4 +- .../Writer/Word2007/Style/Paragraph.php | 6 +- src/PhpWord/Writer/Word2007/Style/Table.php | 16 +- tests/PhpWord/Shared/XMLWriterTest.php | 74 +++++++ tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- 35 files changed, 362 insertions(+), 104 deletions(-) create mode 100644 src/PhpWord/Shared/XMLWriter.php create mode 100644 tests/PhpWord/Shared/XMLWriterTest.php diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php new file mode 100644 index 00000000..1d825dec --- /dev/null +++ b/src/PhpWord/Shared/XMLWriter.php @@ -0,0 +1,184 @@ +openMemory(); + } else { + if (!is_dir($pTemporaryStorageDir)) { + $pTemporaryStorageDir = sys_get_temp_dir(); + } + // Create temporary filename + $this->tempFileName = @tempnam($pTemporaryStorageDir, 'xml'); + + // Open storage + $this->openUri($this->tempFileName); + } + + if ($compatibility) { + $this->setIndent(false); + $this->setIndentString(''); + } else { + $this->setIndent(true); + $this->setIndentString(' '); + } + } + + /** + * Destructor + */ + public function __destruct() + { + // Unlink temporary files + if (empty($this->tempFileName)) { + return; + } + if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) { + throw new \Exception('The file '.$this->tempFileName.' could not be deleted.'); + } + } + + /** + * Get written data + * + * @return string + */ + public function getData() + { + if ($this->tempFileName == '') { + return $this->outputMemory(true); + } + + $this->flush(); + return file_get_contents($this->tempFileName); + } + + + /** + * Write simple element and attribute(s) block + * + * There are two options: + * 1. If the `$attributes` is an array, then it's an associative array of attributes + * 2. If not, then it's a simple attribute-value pair + * + * @param string $element + * @param string|array $attributes + * @param string $value + * @return void + */ + public function writeElementBlock($element, $attributes, $value = null) + { + $this->startElement($element); + if (!is_array($attributes)) { + $attributes = array($attributes => $value); + } + foreach ($attributes as $attribute => $value) { + $this->writeAttribute($attribute, $value); + } + $this->endElement(); + } + + /** + * Write element if ... + * + * @param bool $condition + * @param string $element + * @param string $attribute + * @param mixed $value + * @return void + */ + public function writeElementIf($condition, $element, $attribute = null, $value = null) + { + if ($condition == true) { + if (is_null($attribute)) { + $this->writeElement($element, $value); + } else { + $this->startElement($element); + $this->writeAttribute($attribute, $value); + $this->endElement(); + } + } + } + + /** + * Write attribute if ... + * + * @param bool $condition + * @param string $attribute + * @param mixed $value + * @return void + */ + public function writeAttributeIf($condition, $attribute, $value) + { + if ($condition == true) { + $this->writeAttribute($attribute, $value); + } + } + + /** + * @param string $name + * @param mixed $value + * @return bool + */ + public function writeAttribute($name, $value) + { + if (is_float($value)) { + $value = json_encode($value); + } + return parent::writeAttribute($name, $value); + } +} diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7806530b..103e1556 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 088330ae..19f5ac96 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; @@ -60,7 +60,7 @@ class Table extends AbstractElement /** * Write column. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) @@ -77,7 +77,7 @@ class Table extends AbstractElement /** * Write row. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index f2844de6..67b7a7ae 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; @@ -36,7 +36,7 @@ abstract class AbstractPart extends Word2007AbstractPart /** * Write common root attributes. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) { @@ -72,7 +72,7 @@ abstract class AbstractPart extends Word2007AbstractPart /** * Write font faces declaration. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ protected function writeFontFaces(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index f0e60441..4a84896d 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; @@ -151,7 +151,7 @@ class Content extends AbstractPart * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeAutoStyles(XMLWriter $xmlWriter) { @@ -173,7 +173,7 @@ class Content extends AbstractPart /** * Write automatic styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeTextStyles(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index f38ad01d..8f3f1fb9 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText meta part writer: meta.xml @@ -86,7 +86,7 @@ class Meta extends AbstractPart /** * Write individual property * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $property * @param string $value * diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index bcd57ad5..c026e7bb 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; @@ -66,7 +66,7 @@ class Styles extends AbstractPart /** * Write default styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeDefault(XMLWriter $xmlWriter) { @@ -118,7 +118,7 @@ class Styles extends AbstractPart /** * Write named styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeNamed(XMLWriter $xmlWriter) { @@ -155,7 +155,7 @@ class Styles extends AbstractPart /** * call writePageLayoutIndiv to write page layout styles for each page * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePageLayout(XMLWriter $xmlWriter) { @@ -169,7 +169,7 @@ class Styles extends AbstractPart /** * Write page layout styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section * @param int $sectionNbr */ @@ -255,7 +255,7 @@ class Styles extends AbstractPart /** * Write master style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeMaster(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 6f83df67..d4ec0f7d 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Text as SharedText; @@ -32,7 +32,7 @@ abstract class AbstractElement /** * XML writer * - * @var \PhpOffice\Common\XMLWriter + * @var \PhpOffice\PhpWord\Shared\XMLWriter */ private $xmlWriter; @@ -58,7 +58,7 @@ abstract class AbstractElement /** * Create new instance * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ @@ -72,7 +72,7 @@ abstract class AbstractElement /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 892da051..8a6aa805 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; @@ -71,7 +71,7 @@ class Container extends AbstractElement /** * Write individual element * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP * @return string diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index b59cf58f..e1754d0f 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; /** @@ -105,7 +105,7 @@ class FormField extends Text * Write textinput. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) @@ -121,7 +121,7 @@ class FormField extends Text * Write checkbox. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) @@ -144,7 +144,7 @@ class FormField extends Text * Write dropdown. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 5bebb89c..8fc4849d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Frame as FrameStyle; diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index edf89b53..e2d0d368 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\SDT as SDTElement; /** @@ -77,7 +77,7 @@ class SDT extends Text * Write text. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePlainText(XMLWriter $xmlWriter) { @@ -89,7 +89,7 @@ class SDT extends Text * Write combo box. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) @@ -108,7 +108,7 @@ class SDT extends Text * Write drop down list. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) @@ -120,7 +120,7 @@ class SDT extends Text * Write date. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeDate(XMLWriter $xmlWriter, SDTElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 250d5c1d..445be7e4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Shape as ShapeElement; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; @@ -77,7 +77,7 @@ class Shape extends AbstractElement /** * Write arc. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) @@ -91,7 +91,7 @@ class Shape extends AbstractElement /** * Write curve. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) @@ -106,7 +106,7 @@ class Shape extends AbstractElement /** * Write line. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) @@ -120,7 +120,7 @@ class Shape extends AbstractElement /** * Write polyline. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) @@ -131,7 +131,7 @@ class Shape extends AbstractElement /** * Write rectangle. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style) diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 94437cbf..78989f81 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; @@ -64,7 +64,7 @@ class TOC extends AbstractElement /** * Write title * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param \PhpOffice\PhpWord\Element\Title $title * @param bool $writeFieldMark @@ -132,7 +132,7 @@ class TOC extends AbstractElement /** * Write style * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent */ @@ -178,7 +178,7 @@ class TOC extends AbstractElement /** * Write TOC Field. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element */ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index c365b028..4067868d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; @@ -71,7 +71,7 @@ class Table extends AbstractElement /** * Write column. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) @@ -93,7 +93,7 @@ class Table extends AbstractElement /** * Write row. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) @@ -119,7 +119,7 @@ class Table extends AbstractElement /** * Write cell. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Cell $cell */ private function writeCell(XMLWriter $xmlWriter, CellElement $cell) diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index ce4e41cb..e14b394e 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\AbstractWriter; @@ -73,7 +73,7 @@ abstract class AbstractPart /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 812d3bf1..e413d273 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; /** @@ -99,7 +99,7 @@ class Chart extends AbstractPart * Write chart * * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeChart(XMLWriter $xmlWriter) { @@ -121,7 +121,7 @@ class Chart extends AbstractPart * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePlotArea(XMLWriter $xmlWriter) { @@ -209,7 +209,7 @@ class Chart extends AbstractPart /** * Write series. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $scatter */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) @@ -294,7 +294,7 @@ class Chart extends AbstractPart /** * Write series items. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type * @param array $values */ @@ -335,7 +335,7 @@ class Chart extends AbstractPart * Write axis * * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type */ private function writeAxis(XMLWriter $xmlWriter, $type) @@ -400,7 +400,7 @@ class Chart extends AbstractPart * Write shape * * @see http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $line */ private function writeShape(XMLWriter $xmlWriter, $line = false) diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 33c9f59e..6bff63ee 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; @@ -70,7 +70,7 @@ class Comments extends AbstractPart /** * Write comment item. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Comment $comment */ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 28a2d294..14fc5853 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 contenttypes part writer: [Content_Types].xml @@ -80,7 +80,7 @@ class ContentTypes extends AbstractPart /** * Write content types element * - * @param \PhpOffice\Common\XMLWriter $xmlWriter XML Writer + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer * @param array $parts * @param bool $isDefault */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index e0cabd7e..09ef13f0 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; @@ -80,7 +80,7 @@ class Document extends AbstractPart /** * Write begin section. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSection(XMLWriter $xmlWriter, Section $section) @@ -95,7 +95,7 @@ class Document extends AbstractPart /** * Write end section. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 59bf1830..34bf737b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Footnote; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -135,7 +135,7 @@ class Footnotes extends AbstractPart /** * Write note item. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Footnote|\PhpOffice\PhpWord\Element\Endnote $element */ protected function writeNote(XMLWriter $xmlWriter, $element) diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 61e5cc23..1b4f01a6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Numbering as NumberingStyle; use PhpOffice\PhpWord\Style\NumberingLevel; @@ -97,7 +97,7 @@ class Numbering extends AbstractPart /** * Write level. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) @@ -137,7 +137,7 @@ class Numbering extends AbstractPart * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @todo Use paragraph style writer */ @@ -169,7 +169,7 @@ class Numbering extends AbstractPart * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @todo Use font style writer */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 661a4fa8..0a3f934e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; /** @@ -49,7 +49,7 @@ class Rels extends AbstractPart /** * Write relationships. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $xmlRels * @param array $mediaRels * @param int $relId @@ -76,7 +76,7 @@ class Rels extends AbstractPart /** * Write media relationships. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId * @param array $mediaRel */ @@ -101,7 +101,7 @@ class Rels extends AbstractPart * Format: * * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId Relationship ID * @param string $type Relationship type * @param string $target Relationship target diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 42d3a5d5..4dd8b8be 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -69,7 +69,7 @@ class Settings extends AbstractPart /** * Write indivual setting, recursive to any child settings. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $settingKey * @param array|string $settingValue */ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index d05338c7..4d8f60c2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -76,7 +76,7 @@ class Styles extends AbstractPart /** * Write default font and other default styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) @@ -161,7 +161,7 @@ class Styles extends AbstractPart /** * Write font style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Font $style */ @@ -229,7 +229,7 @@ class Styles extends AbstractPart /** * Write paragraph style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Paragraph $style */ @@ -261,7 +261,7 @@ class Styles extends AbstractPart /** * Write table style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Table $style */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 877ff1db..7e17fbe7 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; /** @@ -30,7 +30,7 @@ abstract class AbstractStyle /** * XML writer * - * @var \PhpOffice\Common\XMLWriter + * @var \PhpOffice\PhpWord\Shared\XMLWriter */ private $xmlWriter; @@ -49,7 +49,7 @@ abstract class AbstractStyle /** * Create new instance. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string|\PhpOffice\PhpWord\Style\AbstractStyle $style */ public function __construct(XMLWriter $xmlWriter, $style = null) @@ -61,7 +61,7 @@ abstract class AbstractStyle /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { @@ -106,7 +106,7 @@ abstract class AbstractStyle /** * Write child style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $name * @param mixed $value */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 10e5b151..782bce52 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -108,7 +108,7 @@ class Frame extends AbstractStyle /** * Write wrap. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style * @param string $wrap */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index f5c4b015..a9929563 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Margin border style writer @@ -78,7 +78,7 @@ class MarginBorder extends AbstractStyle /** * Write side. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $side * @param int $width * @param string $color diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 67616086..08987a6a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -146,7 +146,7 @@ class Paragraph extends AbstractStyle /** * Write tabs. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Tab[] $tabs */ private function writeTabs(XMLWriter $xmlWriter, $tabs) @@ -164,7 +164,7 @@ class Paragraph extends AbstractStyle /** * Write numbering. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $numbering */ private function writeNumbering(XMLWriter $xmlWriter, $numbering) diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 443d6705..eb040e01 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment; @@ -59,7 +59,7 @@ class Table extends AbstractStyle /** * Write full style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) @@ -106,7 +106,7 @@ class Table extends AbstractStyle /** * Enable/Disable automatic resizing of the table * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $layout autofit / fixed */ private function writeLayout(XMLWriter $xmlWriter, $layout) @@ -119,7 +119,7 @@ class Table extends AbstractStyle /** * Write margin. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) @@ -138,7 +138,7 @@ class Table extends AbstractStyle /** * Write border. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) @@ -158,7 +158,7 @@ class Table extends AbstractStyle /** * Writes a table width * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $elementName * @param string $unit * @param int|float $width @@ -177,7 +177,7 @@ class Table extends AbstractStyle /** * Write row style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) @@ -196,7 +196,7 @@ class Table extends AbstractStyle /** * Write shading. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php new file mode 100644 index 00000000..e717ba03 --- /dev/null +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -0,0 +1,74 @@ +startElement('element'); + $object->text('AAA'); + $object->endElement(); + $this->assertEquals('AAA'.chr(10), $object->getData()); + + // Disk + $object = new XMLWriter(XMLWriter::STORAGE_DISK); + $object->startElement('element'); + $object->text('BBB'); + $object->endElement(); + $this->assertEquals('BBB'.chr(10), $object->getData()); + } + + public function testWriteAttribute() + { + $xmlWriter = new XMLWriter(); + $xmlWriter->startElement('element'); + $xmlWriter->writeAttribute('name', 'value'); + $xmlWriter->endElement(); + + $this->assertSame('' . chr(10), $xmlWriter->getData()); + } + + public function testWriteAttributeShouldWriteFloatValueLocaleIndependent() + { + $value = 1.2; + + $xmlWriter = new XMLWriter(); + $xmlWriter->startElement('element'); + $xmlWriter->writeAttribute('name', $value); + $xmlWriter->endElement(); + + $currentLocale = setlocale(LC_NUMERIC, 0); + + setlocale(LC_NUMERIC, 'de_DE.UTF-8', 'de'); + + $this->assertSame('1,2', (string)$value); + $this->assertSame('' . chr(10), $xmlWriter->getData()); + + setlocale(LC_NUMERIC, $currentLocale); + } +} diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index eda4568d..8b827347 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index b1bf417d..bf8a3dd1 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Style subnamespace diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index e799e022..8193b3db 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 48cff871..8bd27980 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style subnamespace From 67b15986a76fb9c938084731105dacd6f087c481 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 08:36:05 +0100 Subject: [PATCH 52/58] remove require phpoffice/common package --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 19997215..7fbf900c 100644 --- a/composer.json +++ b/composer.json @@ -60,8 +60,7 @@ "require": { "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", - "laminas/laminas-escaper": "^2.2", - "phpoffice/common": "^0.2.9" + "laminas/laminas-escaper": "^2.2" }, "require-dev": { "ext-zip": "*", From 681d5c47094462fe7ad2945cecb904cd3d645280 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 09:08:43 +0100 Subject: [PATCH 53/58] fix PHP 8.0 compatibility --- src/PhpWord/Shared/XMLReader.php | 8 ++++++-- tests/PhpWord/Shared/XMLWriterTest.php | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 77013f6c..ca5cb558 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -72,10 +72,14 @@ class XMLReader */ public function getDomFromString($content) { - $originalLibXMLEntityValue = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $originalLibXMLEntityValue = libxml_disable_entity_loader(true); + } $this->dom = new \DOMDocument(); $this->dom->loadXML($content); - libxml_disable_entity_loader($originalLibXMLEntityValue); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($originalLibXMLEntityValue); + } return $this->dom; } diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php index e717ba03..843ae716 100644 --- a/tests/PhpWord/Shared/XMLWriterTest.php +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -66,7 +66,6 @@ class XMLWriterTest extends \PHPUnit\Framework\TestCase setlocale(LC_NUMERIC, 'de_DE.UTF-8', 'de'); - $this->assertSame('1,2', (string)$value); $this->assertSame('' . chr(10), $xmlWriter->getData()); setlocale(LC_NUMERIC, $currentLocale); From 7a131d0ae18ab7718e7443cf0f26bee390b81faa Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 09:37:43 +0100 Subject: [PATCH 54/58] allow dompdf/dompdf 1.0 version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7fbf900c..64363fe1 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,7 @@ "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", - "dompdf/dompdf":"0.8.*", + "dompdf/dompdf":"0.8.* || 1.0.*", "tecnickcom/tcpdf": "6.*", "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" From ea917c28daa8c8f7f7b06477aae4a1faae537654 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 10 Jan 2021 14:06:19 +0100 Subject: [PATCH 55/58] fix coverage --- src/PhpWord/Shared/Drawing.php | 26 ++++++++++++----- src/PhpWord/Shared/Text.php | 29 ++++++++++--------- src/PhpWord/Shared/XMLReader.php | 9 +++--- src/PhpWord/Shared/XMLWriter.php | 8 ++--- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- .../Writer/ODText/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- .../Word2007/Element/AbstractElement.php | 2 +- .../Writer/Word2007/Element/Container.php | 2 +- .../Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Table.php | 2 +- .../Writer/Word2007/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- .../Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 +- .../Writer/Word2007/Style/AbstractStyle.php | 2 +- tests/PhpWord/Shared/DrawingTest.php | 22 ++++---------- tests/PhpWord/Shared/TextTest.php | 7 ++--- tests/PhpWord/Shared/XMLReaderTest.php | 6 ++-- tests/PhpWord/Shared/XMLWriterTest.php | 10 +++---- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- 29 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 25110582..531ee245 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -46,6 +46,7 @@ class Drawing if ($pValue == 0) { return 0; } + return round($pValue / 9525); } @@ -71,9 +72,10 @@ class Drawing if ($pValue == 0) { return 0; } - return ((($pValue * 1.333333333) / self::DPI_96) * 2.54); + + return (($pValue * 1.333333333) / self::DPI_96) * 2.54; } - + /** * Convert points width to pixels * @@ -85,6 +87,7 @@ class Drawing if ($pValue == 0) { return 0; } + return $pValue * 1.333333333; } @@ -97,7 +100,7 @@ class Drawing public static function pixelsToCentimeters($pValue = 0) { //return $pValue * 0.028; - return (($pValue / self::DPI_96) * 2.54); + return ($pValue / self::DPI_96) * 2.54; } /** @@ -111,6 +114,7 @@ class Drawing if ($pValue == 0) { return 0; } + return ($pValue / 2.54) * self::DPI_96; } @@ -136,13 +140,14 @@ class Drawing if ($pValue == 0) { return 0; } + return round($pValue / 60000); } /** * Convert centimeters width to twips * - * @param integer $pValue + * @param int $pValue * @return float */ public static function centimetersToTwips($pValue = 0) @@ -150,13 +155,14 @@ class Drawing if ($pValue == 0) { return 0; } + return $pValue * 566.928; } /** * Convert twips width to centimeters * - * @param integer $pValue + * @param int $pValue * @return float */ public static function twipsToCentimeters($pValue = 0) @@ -164,13 +170,14 @@ class Drawing if ($pValue == 0) { return 0; } + return $pValue / 566.928; } /** * Convert inches width to twips * - * @param integer $pValue + * @param int $pValue * @return float */ public static function inchesToTwips($pValue = 0) @@ -178,13 +185,14 @@ class Drawing if ($pValue == 0) { return 0; } + return $pValue * 1440; } /** * Convert twips width to inches * - * @param integer $pValue + * @param int $pValue * @return float */ public static function twipsToInches($pValue = 0) @@ -192,13 +200,14 @@ class Drawing if ($pValue == 0) { return 0; } + return $pValue / 1440; } /** * Convert twips width to pixels * - * @param integer $pValue + * @param int $pValue * @return float */ public static function twipsToPixels($pValue = 0) @@ -206,6 +215,7 @@ class Drawing if ($pValue == 0) { return 0; } + return round($pValue / 15.873984); } diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index b9bea3ad..c4a1ad62 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -36,8 +36,8 @@ class Text { for ($i = 0; $i <= 19; ++$i) { if ($i != 9 && $i != 10 && $i != 13) { - $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; - $replace = chr($i); + $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; + $replace = chr($i); self::$controlCharacters[$find] = $replace; } } @@ -69,7 +69,7 @@ class Text /** * Return a number formatted for being integrated in xml files * @param float $number - * @param integer $decimals + * @param int $decimals * @return string */ public static function numberFormat($number, $decimals) @@ -79,24 +79,25 @@ class Text /** * @param int $dec - * @link http://stackoverflow.com/a/7153133/2235790 + * @see http://stackoverflow.com/a/7153133/2235790 * @author velcrow * @return string */ public static function chr($dec) { - if ($dec<=0x7F) { + if ($dec <= 0x7F) { return chr($dec); } - if ($dec<=0x7FF) { - return chr(($dec>>6)+192).chr(($dec&63)+128); + if ($dec <= 0x7FF) { + return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128); } - if ($dec<=0xFFFF) { - return chr(($dec>>12)+224).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + if ($dec <= 0xFFFF) { + return chr(($dec >> 12) + 224) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128); } - if ($dec<=0x1FFFFF) { - return chr(($dec>>18)+240).chr((($dec>>12)&63)+128).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + if ($dec <= 0x1FFFFF) { + return chr(($dec >> 18) + 240) . chr((($dec >> 12) & 63) + 128) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128); } + return ''; } @@ -119,7 +120,7 @@ class Text * Check if a string contains UTF-8 data * * @param string $value - * @return boolean + * @return bool */ public static function isUTF8($value = '') { @@ -161,7 +162,7 @@ class Text * @param string $text UTF8 text * @return array * @since 0.11.0 - * @link http://www.randomchaos.com/documents/?source=php_and_unicode + * @see http://www.randomchaos.com/documents/?source=php_and_unicode */ public static function utf8ToUnicode($text) { @@ -201,7 +202,7 @@ class Text * @param array $unicode * @return string * @since 0.11.0 - * @link http://www.randomchaos.com/documents/?source=php_and_unicode + * @see http://www.randomchaos.com/documents/?source=php_and_unicode */ private static function unicodeToEntities($unicode) { diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index ca5cb558..3905c52f 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -43,8 +43,8 @@ class XMLReader * * @param string $zipFile * @param string $xmlFile - * @return \DOMDocument|false * @throws \Exception + * @return \DOMDocument|false */ public function getDomFromZip($zipFile, $xmlFile) { @@ -112,8 +112,8 @@ class XMLReader * * @param string $prefix The prefix * @param string $namespaceURI The URI of the namespace - * @return bool true on success or false on failure * @throws \InvalidArgumentException If called before having loaded the DOM document + * @return bool true on success or false on failure */ public function registerNamespace($prefix, $namespaceURI) { @@ -123,6 +123,7 @@ class XMLReader if ($this->xpath === null) { $this->xpath = new \DOMXpath($this->dom); } + return $this->xpath->registerNamespace($prefix, $namespaceURI); } @@ -192,7 +193,7 @@ class XMLReader * * @param string $path * @param \DOMElement $contextNode - * @return integer + * @return int */ public function countElements($path, \DOMElement $contextNode = null) { @@ -206,7 +207,7 @@ class XMLReader * * @param string $path * @param \DOMElement $contextNode - * @return boolean + * @return bool */ public function elementExists($path, \DOMElement $contextNode = null) { diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 1d825dec..930ad62e 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -88,7 +88,7 @@ class XMLWriter extends \XMLWriter return; } if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) { - throw new \Exception('The file '.$this->tempFileName.' could not be deleted.'); + throw new \Exception('The file ' . $this->tempFileName . ' could not be deleted.'); } } @@ -104,10 +104,10 @@ class XMLWriter extends \XMLWriter } $this->flush(); + return file_get_contents($this->tempFileName); } - /** * Write simple element and attribute(s) block * @@ -118,7 +118,6 @@ class XMLWriter extends \XMLWriter * @param string $element * @param string|array $attributes * @param string $value - * @return void */ public function writeElementBlock($element, $attributes, $value = null) { @@ -139,7 +138,6 @@ class XMLWriter extends \XMLWriter * @param string $element * @param string $attribute * @param mixed $value - * @return void */ public function writeElementIf($condition, $element, $attribute = null, $value = null) { @@ -160,7 +158,6 @@ class XMLWriter extends \XMLWriter * @param bool $condition * @param string $attribute * @param mixed $value - * @return void */ public function writeAttributeIf($condition, $attribute, $value) { @@ -179,6 +176,7 @@ class XMLWriter extends \XMLWriter if (is_float($value)) { $value = json_encode($value); } + return parent::writeAttribute($name, $value); } } diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 103e1556..fa8d8e65 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\Text; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; class TemplateProcessor diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 19f5ac96..adcf8ab4 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Table element writer diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 67b7a7ae..4a7ace78 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart as Word2007AbstractPart; diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 4a84896d..b6a1c95e 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; @@ -26,6 +25,7 @@ use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index c026e7bb..befd23a2 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index d4ec0f7d..ee0fb2f9 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Text as SharedText; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Abstract element writer diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 8a6aa805..0a39403d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Container element writer (section, textrun, header, footnote, cell, etc.) diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index e1754d0f..72063864 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * FormField element writer diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 8fc4849d..f136ba0b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index e2d0d368..e4964242 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\SDT as SDTElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Structured document tag element writer diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 445be7e4..ef30c484 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Shape as ShapeElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 78989f81..3dac76fb 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 4067868d..25a44fb1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Cell as CellStyle; use PhpOffice\PhpWord\Style\Row as RowStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Cell as CellStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index e14b394e..4bee5c54 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\AbstractWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index e413d273..8907160b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 chart part writer: word/charts/chartx.xml diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 6bff63ee..5b867324 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 09ef13f0..d2ab836b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 34bf737b..58c2e9b1 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 0a3f934e..70f632f7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 main relationship writer: _rels/.rels diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 7e17fbe7..3624a7be 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Style writer diff --git a/tests/PhpWord/Shared/DrawingTest.php b/tests/PhpWord/Shared/DrawingTest.php index 906a32ce..b7110923 100644 --- a/tests/PhpWord/Shared/DrawingTest.php +++ b/tests/PhpWord/Shared/DrawingTest.php @@ -20,12 +20,10 @@ namespace PhpOffice\PhpWord\Shared; /** * Test class for PhpOffice\PhpWord\Shared\Drawing * - * @coversDefaultClass PhpOffice\PhpWord\Shared\Drawing + * @coversDefaultClass \PhpOffice\PhpWord\Shared\Drawing */ class DrawingTest extends \PHPUnit\Framework\TestCase { - /** - */ public function testDegreesAngle() { $value = rand(1, 100); @@ -36,8 +34,6 @@ class DrawingTest extends \PHPUnit\Framework\TestCase $this->assertEquals(round($value / 60000), Drawing::angleToDegrees($value)); } - /** - */ public function testPixelsCentimeters() { $value = rand(1, 100); @@ -48,32 +44,26 @@ class DrawingTest extends \PHPUnit\Framework\TestCase $this->assertEquals($value / 2.54 * Drawing::DPI_96, Drawing::centimetersToPixels($value)); } - /** - */ public function testPixelsEMU() { $value = rand(1, 100); $this->assertEquals(0, Drawing::pixelsToEmu()); - $this->assertEquals(round($value*9525), Drawing::pixelsToEmu($value)); + $this->assertEquals(round($value * 9525), Drawing::pixelsToEmu($value)); $this->assertEquals(0, Drawing::emuToPixels()); - $this->assertEquals(round($value/9525), Drawing::emuToPixels($value)); + $this->assertEquals(round($value / 9525), Drawing::emuToPixels($value)); } - /** - */ public function testPixelsPoints() { $value = rand(1, 100); $this->assertEquals(0, Drawing::pixelsToPoints()); - $this->assertEquals($value*0.67777777, Drawing::pixelsToPoints($value)); + $this->assertEquals($value * 0.67777777, Drawing::pixelsToPoints($value)); $this->assertEquals(0, Drawing::pointsToPixels()); - $this->assertEquals($value* 1.333333333, Drawing::pointsToPixels($value)); + $this->assertEquals($value * 1.333333333, Drawing::pointsToPixels($value)); } - /** - */ public function testPointsCentimeters() { $value = rand(1, 100); @@ -82,8 +72,6 @@ class DrawingTest extends \PHPUnit\Framework\TestCase $this->assertEquals($value * 1.333333333 / Drawing::DPI_96 * 2.54, Drawing::pointsToCentimeters($value)); } - /** - */ public function testTwips() { $value = rand(1, 100); diff --git a/tests/PhpWord/Shared/TextTest.php b/tests/PhpWord/Shared/TextTest.php index ded00e96..6df19b12 100644 --- a/tests/PhpWord/Shared/TextTest.php +++ b/tests/PhpWord/Shared/TextTest.php @@ -20,12 +20,10 @@ namespace PhpOffice\PhpWord\Shared; /** * Test class for Text * - * @coversDefaultClass PhpOffice\PhpWord\Shared\Text + * @coversDefaultClass \PhpOffice\PhpWord\Shared\Text */ class TextTest extends \PHPUnit\Framework\TestCase { - /** - */ public function testControlCharacters() { $this->assertEquals('', Text::controlCharacterPHP2OOXML()); @@ -33,7 +31,7 @@ class TextTest extends \PHPUnit\Framework\TestCase $this->assertEquals('àéîöù', Text::controlCharacterPHP2OOXML('àéîöù')); $value = rand(0, 8); - $this->assertEquals('_x'.sprintf('%04s', strtoupper(dechex($value))).'_', Text::controlCharacterPHP2OOXML(chr($value))); + $this->assertEquals('_x' . sprintf('%04s', strtoupper(dechex($value))) . '_', Text::controlCharacterPHP2OOXML(chr($value))); $this->assertEquals('', Text::controlCharacterOOXML2PHP('')); $this->assertEquals(chr(0x08), Text::controlCharacterOOXML2PHP('_x0008_')); @@ -58,6 +56,7 @@ class TextTest extends \PHPUnit\Framework\TestCase $this->assertEquals('🌃', Text::chr(0x1F303)); $this->assertEquals('', Text::chr(2097152)); } + /** * Is UTF8 */ diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php index a34d650a..4d0ee64c 100644 --- a/tests/PhpWord/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -20,7 +20,7 @@ namespace PhpOffice\PhpWord\Shared; /** * Test class for XMLReader * - * @coversDefaultClass PhpOffice\PhpWord\Shared\XMLReader + * @coversDefaultClass \PhpOffice\PhpWord\Shared\XMLReader */ class XMLReaderTest extends \PHPUnit\Framework\TestCase { @@ -57,7 +57,7 @@ class XMLReaderTest extends \PHPUnit\Framework\TestCase /** * Test that read from non existing archive throws exception * - * @expectedException Exception + * @expectedException \Exception */ public function testThrowsExceptionOnNonExistingArchive() { @@ -124,7 +124,7 @@ class XMLReaderTest extends \PHPUnit\Framework\TestCase /** * Test that xpath fails if custom namespace is not registered * - * @expectedException InvalidArgumentException + * @expectedException \InvalidArgumentException */ public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc() { diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php index 843ae716..e86cd50b 100644 --- a/tests/PhpWord/Shared/XMLWriterTest.php +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -24,23 +24,21 @@ namespace PhpOffice\PhpWord\Shared; */ class XMLWriterTest extends \PHPUnit\Framework\TestCase { - /** - */ public function testConstruct() { // Memory $object = new XMLWriter(); $object->startElement('element'); - $object->text('AAA'); + $object->text('AAA'); $object->endElement(); - $this->assertEquals('AAA'.chr(10), $object->getData()); + $this->assertEquals('AAA' . chr(10), $object->getData()); // Disk $object = new XMLWriter(XMLWriter::STORAGE_DISK); $object->startElement('element'); - $object->text('BBB'); + $object->text('BBB'); $object->endElement(); - $this->assertEquals('BBB'.chr(10), $object->getData()); + $this->assertEquals('BBB' . chr(10), $object->getData()); } public function testWriteAttribute() diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 8193b3db..38b1ba75 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -17,11 +17,11 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** From 293efab0c2bcbfa4331ca6594f5c5a51d83c9c3b Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 10 Jan 2021 14:33:13 +0100 Subject: [PATCH 56/58] TCPDF doesn't support PHP 8.0, skip test --- tests/PhpWord/Writer/PDF/TCPDFTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index c8f5d222..53e55ca0 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -39,6 +39,12 @@ class TCPDFTest extends \PHPUnit\Framework\TestCase return; } + // TCPDF version 6.3.5 doesn't support PHP 8.0, fixed via https://github.com/tecnickcom/TCPDF/pull/293, + // pending new release. + if (version_compare(PHP_VERSION, '8.0.0', '>=')) { + return; + } + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); From 40966dd5c5fb1f7f02950fac82e4ee2eadc2f58b Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 10 Jan 2021 14:56:54 +0100 Subject: [PATCH 57/58] remove allow failures for PHP 8.0 --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index aca5dbf8..c368913d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,8 +24,6 @@ matrix: dist: trusty - php: 7.0 env: COVERAGE=1 - - php: 8.0 - env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 dist: xenial @@ -33,8 +31,6 @@ matrix: dist: xenial - php: 5.5 dist: xenial - allow_failures: - - php: 8.0 cache: directories: From ca1272bd695ad88c4eff6c4abc0d9bab81ae5d72 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 5 Feb 2021 20:48:05 +0100 Subject: [PATCH 58/58] remove whitespace --- tests/PhpWord/Reader/Word2007/ElementTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index d5db6be8..08b72418 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -64,7 +64,7 @@ class ElementTest extends AbstractTestReader $text = $elements[0]; $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); } - + /** * Test reading of textbreak */