From 913ac5a4da9daaf5ce716d4cee3e79b76f85201e Mon Sep 17 00:00:00 2001 From: Nextpage <92269411+nxtpge@users.noreply.github.com> Date: Sun, 4 Jun 2023 11:26:11 +0200 Subject: [PATCH 01/24] Template : Set a checkbox --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/template.md | 25 +++ mkdocs.yml | 1 + samples/Sample_42_TemplateSetCheckbox.php | 21 +++ ...TLDefault.php => Sample_43_RTLDefault.php} | 0 .../Sample_42_TemplateSetCheckbox.docx | Bin 0 -> 13161 bytes src/PhpWord/TemplateProcessor.php | 21 +++ tests/PhpWordTests/TemplateProcessorTest.php | 153 ++++++++++++++++++ 8 files changed, 222 insertions(+) create mode 100644 samples/Sample_42_TemplateSetCheckbox.php rename samples/{Sample_52_RTLDefault.php => Sample_43_RTLDefault.php} (100%) create mode 100644 samples/resources/Sample_42_TemplateSetCheckbox.docx diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 1b8e1daea9..d52fa01e7e 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -29,6 +29,7 @@ - PDF Writer : Added support for PageBreak - PDF Writer : Added callback for modifying the HTML - Added Support for Language, both for document overall and individual text elements +- Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509) ### Bug fixes diff --git a/docs/usage/template.md b/docs/usage/template.md index 17612357fd..a0c885e75e 100644 --- a/docs/usage/template.md +++ b/docs/usage/template.md @@ -38,6 +38,31 @@ You can also set multiple values by passing all of them in an array. $templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe')); ``` +## setCheckbox + +Given a template containing a checkbox control with the title or tag named: + +``` clean +${checkbox} +``` +The following will check the checkbox: + +``` php +setCheckbox('checkbox', true); +``` + +!!! note annotate "To add a checkbox and set its title or tag in a template" + + 1. Go to **Developer** tab > **Controls** group + 2. Select the **Check Box Content Control** + 3. Right-click on your checkbox + 4. Click on **Properties** + 5. Set the title or the tag + + These steps may change regarding the version of Microsoft Word used. + ## setMacroOpeningChars You can define a custom opening macro. The following will set ``{#`` as the opening search pattern. diff --git a/mkdocs.yml b/mkdocs.yml index 5618dec88c..a58ebfdad6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -55,6 +55,7 @@ nav: - Comment: 'usage/elements/comment.md' - Field: 'usage/elements/field.md' - Footnote & Endnote: 'usage/elements/note.md' + - Formula: 'usage/elements/formula.md' - Image: 'usage/elements/image.md' - Line: 'usage/elements/line.md' - Link: 'usage/elements/link.md' diff --git a/samples/Sample_42_TemplateSetCheckbox.php b/samples/Sample_42_TemplateSetCheckbox.php new file mode 100644 index 0000000000..9386a191b0 --- /dev/null +++ b/samples/Sample_42_TemplateSetCheckbox.php @@ -0,0 +1,21 @@ +setCheckbox('checkbox', true); +$templateProcessor->setCheckbox('checkbox2', false); + +echo date('H:i:s'), ' Saving the result document...', EOL; +$templateProcessor->saveAs(__DIR__ . "/results/{$filename}"); + +echo getEndingNotes(['Word2007' => 'docx'], "results/{$filename}"); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_52_RTLDefault.php b/samples/Sample_43_RTLDefault.php similarity index 100% rename from samples/Sample_52_RTLDefault.php rename to samples/Sample_43_RTLDefault.php diff --git a/samples/resources/Sample_42_TemplateSetCheckbox.docx b/samples/resources/Sample_42_TemplateSetCheckbox.docx new file mode 100644 index 0000000000000000000000000000000000000000..9abc486b697bfe11d0ec3a17f82539d61ead58fa GIT binary patch literal 13161 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 Hzn%R*;!B@5 literal 0 HcmV?d00001 diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f740212a2c..1ad901d480 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -372,6 +372,27 @@ public function setValues(array $values): void } } + public function setCheckbox(string $search, bool $checked): void + { + $search = static::ensureMacroCompleted($search); + $blockType = 'w:sdt'; + + $where = $this->findContainingXmlBlockForMacro($search, $blockType); + if (!is_array($where)) { + return; + } + + $block = $this->getSlice($where['start'], $where['end']); + + $val = $checked ? '1' : '0'; + $block = preg_replace('/()/', '$1"' . $val . '"$2', $block); + + $text = $checked ? '☒' : '☐'; + $block = preg_replace('/().*?(<\/w:t>)/', '$1' . $text . '$2', $block); + + $this->replaceXmlBlock($search, $block, $blockType); + } + /** * @param string $search */ diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 843ac798e2..f2d2cfbf13 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -610,6 +610,159 @@ public function testSetValuesWithCustomMacro(): void self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart()); } + /** + * @covers ::setCheckbox + */ + public function testSetCheckbox(): void + { + $mainPart = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $result = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setCheckbox('checkbox', true); + $templateProcessor->setCheckbox('checkbox2', false); + + self::assertEquals(preg_replace('/>\s+<', $result), preg_replace('/>\s+<', $templateProcessor->getMainPart())); + } + + /** + * @covers ::setCheckbox + */ + public function testSetCheckboxWithCustomMacro(): void + { + $mainPart = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $result = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setMacroChars('{#', '#}'); + $templateProcessor->setCheckbox('checkbox', true); + $templateProcessor->setCheckbox('checkbox2', false); + + self::assertEquals(preg_replace('/>\s+<', $result), preg_replace('/>\s+<', $templateProcessor->getMainPart())); + } + /** * @covers ::setImageValue */ From a209906f3d64d4327afbf09b49c6466c209e13db Mon Sep 17 00:00:00 2001 From: milkyway Date: Tue, 7 Nov 2023 07:11:06 +0100 Subject: [PATCH 02/24] Added field 'FILENAME' --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/elements/field.md | 3 +- samples/Sample_27_Field.php | 3 + src/PhpWord/Element/Field.php | 6 ++ src/PhpWord/Writer/ODText/Element/Field.php | 15 ++++- src/PhpWord/Writer/RTF/Element/Field.php | 19 +++++- src/PhpWord/Writer/Word2007/Element/Field.php | 22 ++++--- .../Writer/ODText/Element/FieldTest.php | 64 +++++++++++++++++++ tests/PhpWordTests/Writer/RTF/ElementTest.php | 18 ++++++ .../Writer/Word2007/ElementTest.php | 38 +++++++++++ 10 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 tests/PhpWordTests/Writer/ODText/Element/FieldTest.php diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index d52fa01e7e..c7ad030b3e 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -30,6 +30,7 @@ - PDF Writer : Added callback for modifying the HTML - Added Support for Language, both for document overall and individual text elements - Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509) +- ODText / RTF / Word2007 Writer : Add field FILENAME by [@milkyway-git](https://github.com/milkyway-git) in [#2510](https://github.com/PHPOffice/PHPWord/pull/2510) ### Bug fixes diff --git a/docs/usage/elements/field.md b/docs/usage/elements/field.md index 10492cc742..fe8e9756fc 100644 --- a/docs/usage/elements/field.md +++ b/docs/usage/elements/field.md @@ -7,6 +7,7 @@ Currently the following fields are supported: - DATE - XE - INDEX +- FILENAME ``` php addField('XE', array(), array(), $fieldText); //this actually adds the index $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); -``` \ No newline at end of file +``` diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index d250946169..fd441ba022 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -26,6 +26,9 @@ $section->addText('Number of pages field:'); $section->addField('NUMPAGES', ['numformat' => '0,00', 'format' => 'Arabic'], ['PreserveFormat']); + +$section->addText('Filename field:'); +$section->addField('FILENAME', ['format' => 'Upper'], ['Path', 'PreserveFormat']); $section->addTextBreak(); $textrun = $section->addTextRun(); diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 68a5296d7a..b371bb80d7 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -85,6 +85,12 @@ class Field extends AbstractElement 'properties' => ['StyleIdentifier' => ''], 'options' => ['PreserveFormat'], ], + 'FILENAME' => [ + 'properties' => [ + 'format' => ['Upper', 'Lower', 'FirstCap', 'Caps'], + ], + 'options' => ['Path', 'PreserveFormat'], + ], ]; /** diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index 1bfdbc9301..46f62b0f02 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ // Not fully implemented -// - supports only PAGE and NUMPAGES +// - supports only PAGE, NUMPAGES, DATE and FILENAME // - supports only default formats and options // - supports style only if specified by name // - spaces before and after field may be dropped @@ -44,6 +44,7 @@ public function write(): void case 'date': case 'page': case 'numpages': + case 'filename': $this->writeDefault($element, $type); break; @@ -78,6 +79,18 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type): $xmlWriter->startElement('text:page-count'); $xmlWriter->endElement(); + break; + case 'filename': + $xmlWriter->startElement('text:file-name'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $options = $element->getOptions(); + if ($options != null && in_array('Path', $options)) { + $xmlWriter->writeAttribute('text:display', 'full'); + } else { + $xmlWriter->writeAttribute('text:display', 'name'); + } + $xmlWriter->endElement(); + break; } $xmlWriter->endElement(); // text:span diff --git a/src/PhpWord/Writer/RTF/Element/Field.php b/src/PhpWord/Writer/RTF/Element/Field.php index 37f203aca8..34024f5e51 100644 --- a/src/PhpWord/Writer/RTF/Element/Field.php +++ b/src/PhpWord/Writer/RTF/Element/Field.php @@ -17,10 +17,12 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; +use PhpOffice\PhpWord\Element\Field as ElementField; + /** * Field element writer. * - * Note: for now, only date, page and numpages fields are implemented for RTF. + * Note: for now, only date, page, numpages and filename fields are implemented for RTF. */ class Field extends Text { @@ -30,7 +32,7 @@ class Field extends Text public function write() { $element = $this->element; - if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + if (!$element instanceof ElementField) { return; } @@ -66,7 +68,18 @@ protected function writeNumpages() return 'NUMPAGES'; } - protected function writeDate(\PhpOffice\PhpWord\Element\Field $element) + protected function writeFilename(ElementField $element): string + { + $content = 'FILENAME'; + $options = $element->getOptions(); + if ($options != null && in_array('Path', $options)) { + $content .= ' \\\\p'; + } + + return $content; + } + + protected function writeDate(ElementField $element) { $content = ''; $content .= 'DATE'; diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 6fdb48b0f4..4d7c2a0b46 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -166,15 +166,15 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele foreach ($properties as $propkey => $propval) { switch ($propkey) { case 'format': - $propertiesAndOptions .= '\* ' . $propval . ' '; + $propertiesAndOptions .= '\\* ' . $propval . ' '; break; case 'numformat': - $propertiesAndOptions .= '\# ' . $propval . ' '; + $propertiesAndOptions .= '\\# ' . $propval . ' '; break; case 'dateformat': - $propertiesAndOptions .= '\@ "' . $propval . '" '; + $propertiesAndOptions .= '\\@ "' . $propval . '" '; break; case 'macroname': @@ -192,27 +192,31 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele foreach ($options as $option) { switch ($option) { case 'PreserveFormat': - $propertiesAndOptions .= '\* MERGEFORMAT '; + $propertiesAndOptions .= '\\* MERGEFORMAT '; break; case 'LunarCalendar': - $propertiesAndOptions .= '\h '; + $propertiesAndOptions .= '\\h '; break; case 'SakaEraCalendar': - $propertiesAndOptions .= '\s '; + $propertiesAndOptions .= '\\s '; break; case 'LastUsedFormat': - $propertiesAndOptions .= '\l '; + $propertiesAndOptions .= '\\l '; break; case 'Bold': - $propertiesAndOptions .= '\b '; + $propertiesAndOptions .= '\\b '; break; case 'Italic': - $propertiesAndOptions .= '\i '; + $propertiesAndOptions .= '\\i '; + + break; + case 'Path': + $propertiesAndOptions .= '\\p '; break; default: diff --git a/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php new file mode 100644 index 0000000000..2d9bb7c87d --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php @@ -0,0 +1,64 @@ +addSection(); + $section->addField('FILENAME'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:span/text:file-name')); + self::assertEquals('false', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:fixed')); + self::assertEquals('name', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:display')); + } + + public function testFieldFilenameOptionPath(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addField('FILENAME', [], ['Path']); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:span/text:file-name')); + self::assertEquals('false', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:fixed')); + self::assertEquals('full', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:display')); + } +} diff --git a/tests/PhpWordTests/Writer/RTF/ElementTest.php b/tests/PhpWordTests/Writer/RTF/ElementTest.php index 7c1549371d..fd0842cd6c 100644 --- a/tests/PhpWordTests/Writer/RTF/ElementTest.php +++ b/tests/PhpWordTests/Writer/RTF/ElementTest.php @@ -45,6 +45,24 @@ public function testUnmatchedElements(): void } } + public function testFilenameField(): void + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('FILENAME'); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + self::assertEquals("{\\field{\\*\\fldinst FILENAME}{\\fldrslt}}\\par\n", $this->removeCr($field)); + } + + public function testFilenameFieldOptionsPath(): void + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('FILENAME', [], ['Path']); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + self::assertEquals("{\\field{\\*\\fldinst FILENAME \\\\p}{\\fldrslt}}\\par\n", $this->removeCr($field)); + } + public function testPageField(): void { $parentWriter = new RTF(); diff --git a/tests/PhpWordTests/Writer/Word2007/ElementTest.php b/tests/PhpWordTests/Writer/Word2007/ElementTest.php index 3bcd842fbd..3ed3e7a91b 100644 --- a/tests/PhpWordTests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Writer/Word2007/ElementTest.php @@ -306,6 +306,44 @@ public function testStyledFieldElement(): void self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); } + public function testFieldElementFilename(): void + { + $phpWord = new PhpWord(); + $stnam = 'h1'; + $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]); + $section = $phpWord->addSection(); + + $fld = $section->addField('FILENAME'); + $fld->setFontStyle($stnam); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(' FILENAME ', $doc->getElement($element)->textContent); + $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr'; + self::assertTrue($doc->elementExists($sty)); + self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); + } + + public function testFieldElementFilenameOptionsPath(): void + { + $phpWord = new PhpWord(); + $stnam = 'h1'; + $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]); + $section = $phpWord->addSection(); + + $fld = $section->addField('FILENAME', [], ['Path']); + $fld->setFontStyle($stnam); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(' FILENAME \p ', $doc->getElement($element)->textContent); + $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr'; + self::assertTrue($doc->elementExists($sty)); + self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); + } + public function testFieldElementWithComplexText(): void { $phpWord = new PhpWord(); From d65be9830f9bdb00ccbcc737b5af4726859d4f9c Mon Sep 17 00:00:00 2001 From: Ethan Merchant <49330364+spatialfree@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:48:56 -0400 Subject: [PATCH 03/24] Word2007 Reader : Check for null on $fontDefaultStyle --- docs/changes/1.x/1.2.0.md | 1 + src/PhpWord/Reader/Word2007/Styles.php | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index c7ad030b3e..9900e7b663 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -41,6 +41,7 @@ - Template Processor : Fixed choose dimention for Float Value by [@gdevilbat](https://github.com/gdevilbat) in GH-2449 - HTML Parser : Fix image parsing from url without extension by [@JokubasR](https://github.com/JokubasR) in GH-2459 - Word2007 Reader : Fixed reading of Office365 DocX file by [@filippotoso](https://github.com/filippotoso) & [@lfglopes](https://github.com/lfglopes) in [#2506](https://github.com/PHPOffice/PHPWord/pull/2506) +- Word2007 Reader : Check for null on $fontDefaultStyle by [@spatialfree](https://github.com/spatialfree) in [#2513](https://github.com/PHPOffice/PHPWord/pull/2513) ### Miscellaneous diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 4566398ad2..760adf9493 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -39,14 +39,16 @@ public function read(PhpWord $phpWord): void $fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault'); if ($fontDefaults !== null) { $fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults); - if (array_key_exists('name', $fontDefaultStyle)) { - $phpWord->setDefaultFontName($fontDefaultStyle['name']); - } - if (array_key_exists('size', $fontDefaultStyle)) { - $phpWord->setDefaultFontSize($fontDefaultStyle['size']); - } - if (array_key_exists('lang', $fontDefaultStyle)) { - $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); + if ($fontDefaultStyle) { + if (array_key_exists('name', $fontDefaultStyle)) { + $phpWord->setDefaultFontName($fontDefaultStyle['name']); + } + if (array_key_exists('size', $fontDefaultStyle)) { + $phpWord->setDefaultFontSize($fontDefaultStyle['size']); + } + if (array_key_exists('lang', $fontDefaultStyle)) { + $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); + } } } From bdcd10492165a14cee552586819c70541da5c4d3 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:20:24 -0800 Subject: [PATCH 04/24] Improve ODText Content Reader Fix #2493. There is much that the ODT Reader ignores. This change adds support for the `text:section`, `text:span`, `text:s`, and `text:tab` tags, thereby handling multiple sections, text runs, tab characters, and multiple spaces. There will still be many omissions (e.g. styles and tables), but you will now often be able to access the text content of valid ODT documents. The issue suggests variations in a simple file created on its own by LibreOffice, and a similar file created by PhpWord. Both are unit-tested. A `getText` method is added to TextRun to facilitate testing (and can be useful on its own). It will return the concatenated texts of all elements of the text run. --- docs/changes/1.x/1.2.0.md | 1 + phpstan-baseline.neon | 5 -- src/PhpWord/Element/TextRun.php | 12 +++ src/PhpWord/Reader/ODText/Content.php | 81 +++++++++++++++-- .../Reader/ODText/ODTextSectionTest.php | 83 ++++++++++++++++++ .../_files/documents/word.2493.nosection.odt | Bin 0 -> 3066 bytes 6 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php create mode 100644 tests/PhpWordTests/_files/documents/word.2493.nosection.odt diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 9900e7b663..30d3b35202 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -31,6 +31,7 @@ - Added Support for Language, both for document overall and individual text elements - Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509) - ODText / RTF / Word2007 Writer : Add field FILENAME by [@milkyway-git](https://github.com/milkyway-git) in [#2510](https://github.com/PHPOffice/PHPWord/pull/2510) +- ODText Reader : Improve Section Reader by [@oleibman](https://github.com/oleibman) in [#2507](https://github.com/PHPOffice/PHPWord/pull/2507) ### Bug fixes diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e7918d9174..2e44745b3d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -165,11 +165,6 @@ parameters: count: 1 path: src/PhpWord/Reader/HTML.php - - - message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" - count: 2 - path: src/PhpWord/Reader/ODText/Content.php - - message: "#^Offset 'textNodes' on array\\{changed\\: PhpOffice\\\\PhpWord\\\\Element\\\\TrackChange, textNodes\\: DOMNodeList\\\\} in isset\\(\\) always exists and is not nullable\\.$#" count: 1 diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index fc8727592a..33c55f6584 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -78,4 +78,16 @@ public function setParagraphStyle($style = null) return $this->paragraphStyle; } + + public function getText(): string + { + $outstr = ''; + foreach ($this->getElements() as $element) { + if ($element instanceof Text) { + $outstr .= $element->getText(); + } + } + + return $outstr; + } } diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 45cb0704db..15c76c27b9 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -18,7 +18,10 @@ namespace PhpOffice\PhpWord\Reader\ODText; use DateTime; +use DOMElement; +use DOMNodeList; use PhpOffice\Math\Reader\MathML; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; @@ -30,6 +33,9 @@ */ class Content extends AbstractPart { + /** @var ?Section */ + private $section; + /** * Read content.xml. */ @@ -41,17 +47,28 @@ public function read(PhpWord $phpWord): void $trackedChanges = []; $nodes = $xmlReader->getElements('office:body/office:text/*'); + $this->section = null; + $this->processNodes($nodes, $xmlReader, $phpWord); + $this->section = null; + } + + /** @param DOMNodeList $nodes */ + public function processNodes(DOMNodeList $nodes, XMLReader $xmlReader, PhpWord $phpWord): void + { if ($nodes->length > 0) { - $section = $phpWord->addSection(); foreach ($nodes as $node) { // $styleName = $xmlReader->getAttribute('text:style-name', $node); switch ($node->nodeName) { case 'text:h': // Heading $depth = $xmlReader->getAttribute('text:outline-level', $node); - $section->addTitle($node->nodeValue, $depth); + $this->getSection($phpWord)->addTitle($node->nodeValue, $depth); break; case 'text:p': // Paragraph + $styleName = $xmlReader->getAttribute('text:style-name', $node); + if (substr($styleName, 0, 2) === 'SB') { + break; + } $element = $xmlReader->getElement('draw:frame/draw:object', $node); if ($element) { $mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml'; @@ -65,11 +82,13 @@ public function read(PhpWord $phpWord): void $reader = new MathML(); $math = $reader->read($mathXML); - $section->addFormula($math); + $this->getSection($phpWord)->addFormula($math); } } } else { $children = $node->childNodes; + $spans = false; + /** @var DOMElement $child */ foreach ($children as $child) { switch ($child->nodeName) { case 'text:change-start': @@ -89,16 +108,49 @@ public function read(PhpWord $phpWord): void $changed = $trackedChanges[$changeId]; } + break; + case 'text:span': + $spans = true; + break; } } - $element = $section->addText($node->nodeValue); + if ($spans) { + $element = $this->getSection($phpWord)->addTextRun(); + foreach ($children as $child) { + switch ($child->nodeName) { + case 'text:span': + /** @var DOMElement $child2 */ + foreach ($child->childNodes as $child2) { + switch ($child2->nodeName) { + case '#text': + $element->addText($child2->nodeValue); + + break; + case 'text:tab': + $element->addText("\t"); + + break; + case 'text:s': + $spaces = (int) $child2->getAttribute('text:c') ?: 1; + $element->addText(str_repeat(' ', $spaces)); + + break; + } + } + + break; + } + } + } else { + $element = $this->getSection($phpWord)->addText($node->nodeValue); + } if (isset($changed) && is_array($changed)) { $element->setTrackChange($changed['changed']); if (isset($changed['textNodes'])) { foreach ($changed['textNodes'] as $changedNode) { - $element = $section->addText($changedNode->nodeValue); + $element = $this->getSection($phpWord)->addText($changedNode->nodeValue); $element->setTrackChange($changed['changed']); } } @@ -110,7 +162,7 @@ public function read(PhpWord $phpWord): void $listItems = $xmlReader->getElements('text:list-item/text:p', $node); foreach ($listItems as $listItem) { // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem); - $section->addListItem($listItem->nodeValue, 0); + $this->getSection($phpWord)->addListItem($listItem->nodeValue, 0); } break; @@ -129,9 +181,26 @@ public function read(PhpWord $phpWord): void $trackedChanges[$changedRegion->getAttribute('text:id')] = ['changed' => $changed, 'textNodes' => $textNodes]; } + break; + case 'text:section': // Section + // $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem); + $this->section = $phpWord->addSection(); + $children = $node->childNodes; + $this->processNodes($children, $xmlReader, $phpWord); + break; } } } } + + private function getSection(PhpWord $phpWord): Section + { + $section = $this->section; + if ($section === null) { + $section = $this->section = $phpWord->addSection(); + } + + return $section; + } } diff --git a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php new file mode 100644 index 0000000000..0a1a4512db --- /dev/null +++ b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php @@ -0,0 +1,83 @@ +filename !== '') { + unlink($this->filename); + $this->filename = ''; + } + } + + public function testWriteThenReadSection(): void + { + $dir = 'tests/PhpWordTests/_files'; + Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $inputText = ['days', 'monday', 'tuesday']; + $inputText[] = "Tab\tthen two spaces then done."; + foreach ($inputText as $text) { + $section->addText($text); + } + $writer = IOFactory::createWriter($phpWord, 'ODText'); + $this->filename = "$dir/sectiontest.odt"; + $writer->save($this->filename); + + $reader = IOFactory::createReader('ODText'); + $phpWord2 = $reader->load($this->filename); + $outputText = []; + foreach ($phpWord2->getSections() as $section) { + foreach ($section->getElements() as $element) { + if (is_object($element) && method_exists($element, 'getText')) { + $outputText[] = $element->getText(); + } + } + } + self::assertSame($inputText, $outputText); + } + + public function testReadNoSections(): void + { + $dir = 'tests/PhpWordTests/_files/documents'; + $inputText = ['days', 'monday', 'tuesday']; + + $reader = IOFactory::createReader('ODText'); + $filename = "$dir/word.2493.nosection.odt"; + $phpWord2 = $reader->load($filename); + $outputText = []; + foreach ($phpWord2->getSections() as $section) { + foreach ($section->getElements() as $element) { + if (is_object($element) && method_exists($element, 'getText')) { + $outputText[] = $element->getText(); + } + } + } + self::assertSame($inputText, $outputText); + } +} diff --git a/tests/PhpWordTests/_files/documents/word.2493.nosection.odt b/tests/PhpWordTests/_files/documents/word.2493.nosection.odt new file mode 100644 index 0000000000000000000000000000000000000000..eb0fa2076433c91a29fd7a2b4db0762c80c7e09d GIT binary patch literal 3066 zcmZ`*2{e>#8-9@`OO&OBO8Bxb`Nvjh?1VxllqE4VGPW7Z*o~!#A;!M%24l-MmZXeq zW6ds2L?mR1QOQ62|98Is>-^vSp6A@}dCz@4=Y8J$z3%HW(x*Gd1sp~{05!Ajlw}pB z-XAU|>Vm`IP$bF?YU}3a470OE!dzXXy;8}zdZL>)v^XN`h zu@?kx0juovLPLTy>ov&lD>K)zY>kg^v;tYEfh`B+`LO06`Q+zxqYgBKO;vs20;RT91F9;kdI!~Ccdy|}CJ8SloH!4~zCtfIxLDIpt% ztoO=uc)~w#P2>t$JUKs_>x`DTdJTf;Qr|mq)%aYC&ecW*v9A=LWFhRAYK;o8*LC;H z4PU#J%3_P(yf|IU6thsBZ(>W@B!eDp$5moK7x=2H$Si+`lOmewRV6u%f7(a2!M<2*6PZ~^} zqDiZtqV|4iC}e1JW$72e@_@S>Y^Bfpy!PN}^*&px^rji#myRFSS2*K&s=U1KYg{fn z*j?VBU&nz}Qmhzt49-2Zf3GZ>-;#<`9a)rFx>B6BhXBts7z#ztH{UTq4L{epy|{4k zb^X?AzV6f-#S7cSnEfxpW9ulH7$)M3qK>D+x1Cg*apN(dZ)SDm`>}apN3@yZb&$r- z=!pq&`HZ*2ibl4HZoB6(r7?bqzYu(@do-XG`I{I}52$B1C*QM3WV~mTBX^8yt^Cb>pAN*$ZoVGA7l_`r7O7uT*)M-)0AHU6MW|u>!?~rywoj{VjkG#&532;s z`5F|-E1DfIUdMMnzy0xT#pk(Zh+H;GrN|TCv^T+ll=ZICwnR(4)D~GDyhQ$EVgj9Z z$Z!zX_qn>1 zLfNJZELgg7O|bffeDa?ss~sbGtDeD=NDZ+ETwa{`v{_}>!1>*;Prk1yZcoxgC*GAS zkzncpyGs^)KDS-lJm5NH^#eclqxB;=d~pQmS)fx)+UFi9636cSz!u_0bGk)JQxlWK zi^M z4kbd3=fc^l4-`!A4+z5WX8FOzgF_VpAFti~rtYo% zRq(n9A$PQ%Kdc~~*62<05;!C>A(lP1t?s1UuL9wlV#`7+TM5fhrPAunD_cRrgqKBo zWt%d%YH=K@m4%7rbqQXiIr;KIP>H_Og!T!1SH- zfA0?1)>{#L3;?#NGmn`%^AJdsGZb;uAG2x9v^+<^y4e}#@4CIoR!GTm1rcU0kwKD1 zfrq;>)l2>*#f-R79U4aP_gZUtfvMJ%Zq}05Kbc5kj1`b;W z5dP3&32jH!K=F-}i)nst&hQTpKApSvr7P*eqRtL^A`LdxC+B4@fpiWuMZ`#J$K?wU z#KfKUAUvnr7X|`M%fL)Td6531gfGscdqpskkd_Kn3cHB{I<0~W{ZmSC8kh8yp}hz3EU3Vl2d`* z<<*v z(r>z2kU^l#DRsKZb0X&)FL>ejE(#zg(R&Pn-8p&7P^y|ajQ%mDO!J*4%V;uEWpz`Q zpU-xXTa=q_w}+EeYj;m8_EBLS4SGBb7eT36ydh%QaA%w&!*{Pl%lx!7=x1`TEyO~a zlM;8%ZjCd}nk-&eJ^Q|Gr;_d|_VRT#{e#|D_WbCMyc(8Kdc< zUEn%*%8Ku5LFRgs&>DlW@cP+2r7YgCRKmdMwmf*x#_7jU&Uaz$Mw98_u`}}bSf3;%xxF>e}*>IS0+tgFS;!ke`lip z(XhC9BE89Q?-KrX^%B5PI#|L1s|$=&ClDw1Y3^gm5+Wi$jCoi3Wxcp{E_KO0iQ8V> z+YM=g`hw;|4s^6IWdLyAm7)1-_d@q-8Li=0$p(6wU@KduPb^VVqWj=Zc05rfEAhgkuZ Date: Sun, 17 Dec 2023 00:20:25 -0800 Subject: [PATCH 05/24] Correct Font Size Calculated by MsDoc Reader Fix #2526. Most of that issue has already been fixed. The one remaining problem was a deprecation message handling font size. The code used `dechex($operand / 2)`, and issued the deprecation message whenever `$operand` was odd because `dechex` is designed only for integer conversion. `$operand` is actually 2 times the point size, so it will be odd only when the point size is some integer plus half a point (no other fractions are allowed). At any rate, it seems that `dechex` should not be used here in the first place; font size is a numeric value, not a hex string. There are many problems with MsDoc Reader at the moment. This PR is narrowly focused on the problem at hand. Its test is, at least, more detailed than the existing MsDoc Reader test, which does nothing more than confirm that read successfully creates a PhpWord object. The new test verifies that the font size is as expected, but does not validate any other aspect of the read. --- src/PhpWord/Reader/MsDoc.php | 2 +- tests/PhpWordTests/Reader/MsDocTest.php | 16 ++++++++++++++++ .../PhpWordTests/_files/documents/word.2526.doc | Bin 0 -> 24576 bytes 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/PhpWordTests/_files/documents/word.2526.doc diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 4cf755e3fa..2599e42350 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1871,7 +1871,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCHps case 0x43: - $oStylePrl->styleFont['size'] = dechex($operand / 2); + $oStylePrl->styleFont['size'] = $operand / 2; break; // sprmCIss diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index deb8b9badd..f5f75ab790 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -60,6 +60,22 @@ public function testLoad(): void self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); } + public function testLoadHalfPointFont(): void + { + $filename = __DIR__ . '/../_files/documents/word.2526.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + $element0 = $elements[0]; + if (method_exists($element0, 'getFontStyle')) { + self::assertSame(19.5, $element0->getFontStyle()->getSize()); + } else { + self::fail('Unexpected no font style for first element'); + } + } + /** * Test exception on not existing file. */ diff --git a/tests/PhpWordTests/_files/documents/word.2526.doc b/tests/PhpWordTests/_files/documents/word.2526.doc new file mode 100644 index 0000000000000000000000000000000000000000..94fc5ed8fd566e4cdaa44b6f1eb8b520773454d1 GIT binary patch literal 24576 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 is)sro_y=Ph`kir6W13Ib^PNe3&!RC Date: Sun, 17 Dec 2023 14:03:54 -0800 Subject: [PATCH 06/24] Suggestions from @Progi1984 --- docs/changes/1.x/1.3.0.md | 14 ++++++++++++++ tests/PhpWordTests/Reader/MsDocTest.php | 2 +- .../{word.2526.doc => reader.font-halfpoint.doc} | Bin 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 docs/changes/1.x/1.3.0.md rename tests/PhpWordTests/_files/documents/{word.2526.doc => reader.font-halfpoint.doc} (100%) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md new file mode 100644 index 0000000000..e85d9ff892 --- /dev/null +++ b/docs/changes/1.x/1.3.0.md @@ -0,0 +1,14 @@ +# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) + +## Enhancements + +### Bug fixes + +- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) Issue [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) PR [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) + +### Miscellaneous + + +### BC Breaks diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index f5f75ab790..cf4db6d0d9 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -62,7 +62,7 @@ public function testLoad(): void public function testLoadHalfPointFont(): void { - $filename = __DIR__ . '/../_files/documents/word.2526.doc'; + $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc '; $phpWord = IOFactory::load($filename, 'MsDoc'); $sections = $phpWord->getSections(); self::assertCount(1, $sections); diff --git a/tests/PhpWordTests/_files/documents/word.2526.doc b/tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc similarity index 100% rename from tests/PhpWordTests/_files/documents/word.2526.doc rename to tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc From ea7a670589a3a1775fe07f9e69350f012985787c Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 17 Dec 2023 14:09:32 -0800 Subject: [PATCH 07/24] Typo Tolerated By Windows but Not By Unix --- tests/PhpWordTests/Reader/MsDocTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index cf4db6d0d9..b62d545de0 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -62,7 +62,7 @@ public function testLoad(): void public function testLoadHalfPointFont(): void { - $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc '; + $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc'; $phpWord = IOFactory::load($filename, 'MsDoc'); $sections = $phpWord->getSections(); self::assertCount(1, $sections); From 0709ae36dd79d49ab3b91bf0cde5e65d0b28c9eb Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 17 Dec 2023 14:16:40 -0800 Subject: [PATCH 08/24] Correct Title Line of Change Log --- docs/changes/1.x/1.3.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index e85d9ff892..e3514080ac 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -1,4 +1,4 @@ -# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) +# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) From bb74fb168e4ae2033337dae303c4156426559b92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:32:29 +0000 Subject: [PATCH 09/24] Bump dompdf/dompdf from 2.0.3 to 2.0.4 Bumps [dompdf/dompdf](https://github.com/dompdf/dompdf) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/dompdf/dompdf/releases) - [Commits](https://github.com/dompdf/dompdf/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: dompdf/dompdf dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.lock | 42 ++++++++++++++++++++------------------- docs/changes/1.x/1.2.0.md | 2 +- docs/changes/1.x/1.3.0.md | 14 ------------- docs/changes/2.x/2.0.0.md | 15 ++++++++++++++ mkdocs.yml | 4 +++- 5 files changed, 41 insertions(+), 36 deletions(-) delete mode 100644 docs/changes/1.x/1.3.0.md create mode 100644 docs/changes/2.x/2.0.0.md diff --git a/composer.lock b/composer.lock index 0f140f1e5a..d1a795a886 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "23680170abecc52de95d0833296ced64", + "content-hash": "8d0272c1442e11290de55a7947fc849c", "packages": [ { "name": "phpoffice/math", @@ -548,16 +548,16 @@ }, { "name": "dompdf/dompdf", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85" + "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/e8d2d5e37e8b0b30f0732a011295ab80680d7e85", - "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f", + "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f", "shasum": "" }, "require": { @@ -604,9 +604,9 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.3" + "source": "https://github.com/dompdf/dompdf/tree/v2.0.4" }, - "time": "2023-02-07T12:51:48+00:00" + "time": "2023-12-12T20:19:39+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -699,16 +699,16 @@ }, { "name": "masterminds/html5", - "version": "2.8.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3" + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3", - "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", "shasum": "" }, "require": { @@ -760,9 +760,9 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.8.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" }, - "time": "2023-04-26T07:27:39+00:00" + "time": "2023-05-10T11:58:31+00:00" }, { "name": "mpdf/mpdf", @@ -1322,16 +1322,16 @@ }, { "name": "phenx/php-svg-lib", - "version": "0.5.0", + "version": "0.5.1", "source": { "type": "git", "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685" + "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8a8a1ebcf6aea861ef30197999f096f7bd4b4456", + "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456", "shasum": "" }, "require": { @@ -1362,9 +1362,9 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0" + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.1" }, - "time": "2022-09-06T12:16:56+00:00" + "time": "2023-12-11T20:56:08+00:00" }, { "name": "php-cs-fixer/diff", @@ -5060,7 +5060,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "phpstan/phpstan-phpunit": 0 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 30d3b35202..265d25b033 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -1,4 +1,4 @@ -# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) +# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md deleted file mode 100644 index e3514080ac..0000000000 --- a/docs/changes/1.x/1.3.0.md +++ /dev/null @@ -1,14 +0,0 @@ -# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) - -## Enhancements - -### Bug fixes - -- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) Issue [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) PR [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) - -### Miscellaneous - - -### BC Breaks diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md new file mode 100644 index 0000000000..cac743cd13 --- /dev/null +++ b/docs/changes/2.x/2.0.0.md @@ -0,0 +1,15 @@ +# [2.0.0](https://github.com/PHPOffice/PHPWord/tree/2.0.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...2.0.0) + +## Enhancements + +### Bug fixes + +- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) + +### Miscellaneous + +- Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) + +### BC Breaks diff --git a/mkdocs.yml b/mkdocs.yml index a58ebfdad6..6eb4d42911 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -86,8 +86,10 @@ nav: - How to: 'howto.md' - Credits: 'credits.md' - Releases: + - '2.x': + - '2.0.0 (WIP)': 'changes/2.x/2.0.0.md' - '1.x': - - '1.2.0 (WIP)': 'changes/1.x/1.2.0.md' + - '1.2.0': 'changes/1.x/1.2.0.md' - '1.1.0': 'changes/1.x/1.1.0.md' - '1.0.0': 'changes/1.x/1.0.0.md' - '0.x': From 9f1d7c75978698f5dbd669b7f10ee2808995ecf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 11:16:57 +0000 Subject: [PATCH 10/24] Bump phpunit/phpunit from 9.6.13 to 9.6.14 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.13 to 9.6.14. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.14/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.13...9.6.14) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 24 ++++++++++++------------ docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index d1a795a886..f69b296d9a 100644 --- a/composer.lock +++ b/composer.lock @@ -1938,16 +1938,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.13", + "version": "9.6.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", + "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", "shasum": "" }, "require": { @@ -2021,7 +2021,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.14" }, "funding": [ { @@ -2037,7 +2037,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:39:22+00:00" + "time": "2023-12-01T06:10:48+00:00" }, { "name": "psr/cache", @@ -5009,16 +5009,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "shasum": "" }, "require": { @@ -5047,7 +5047,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" }, "funding": [ { @@ -5055,7 +5055,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2023-11-20T00:12:19+00:00" } ], "aliases": [], diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index cac743cd13..7bb462acfe 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -11,5 +11,6 @@ ### Miscellaneous - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) +- Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) ### BC Breaks From d60f1e01678ee1eaa61b7a193ab33abf7b4a5b11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 08:41:02 +0000 Subject: [PATCH 11/24] Bump mpdf/mpdf from 8.2.0 to 8.2.2 Bumps [mpdf/mpdf](https://github.com/mpdf/mpdf) from 8.2.0 to 8.2.2. - [Release notes](https://github.com/mpdf/mpdf/releases) - [Changelog](https://github.com/mpdf/mpdf/blob/development/CHANGELOG.md) - [Commits](https://github.com/mpdf/mpdf/compare/v8.2.0...v8.2.2) --- updated-dependencies: - dependency-name: mpdf/mpdf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 40 +++++++++++++++++++-------------------- docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/composer.lock b/composer.lock index f69b296d9a..a281bac14b 100644 --- a/composer.lock +++ b/composer.lock @@ -766,16 +766,16 @@ }, { "name": "mpdf/mpdf", - "version": "v8.2.0", + "version": "v8.2.2", "source": { "type": "git", "url": "https://github.com/mpdf/mpdf.git", - "reference": "170a236a588d177c2aa7447ce490a030ca68e6f4" + "reference": "596a87b876d7793be7be060a8ac13424de120dd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/170a236a588d177c2aa7447ce490a030ca68e6f4", - "reference": "170a236a588d177c2aa7447ce490a030ca68e6f4", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/596a87b876d7793be7be060a8ac13424de120dd5", + "reference": "596a87b876d7793be7be060a8ac13424de120dd5", "shasum": "" }, "require": { @@ -785,7 +785,7 @@ "mpdf/psr-log-aware-trait": "^2.0 || ^3.0", "myclabs/deep-copy": "^1.7", "paragonie/random_compat": "^1.4|^2.0|^9.99.99", - "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "psr/http-message": "^1.0 || ^2.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "setasign/fpdi": "^2.1" @@ -843,20 +843,20 @@ "type": "custom" } ], - "time": "2023-09-01T11:44:52+00:00" + "time": "2023-11-07T13:52:14+00:00" }, { "name": "mpdf/psr-http-message-shim", - "version": "2.0.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/mpdf/psr-http-message-shim.git", - "reference": "1cf4c0b68b8461cea27411ff961482ce7687e34f" + "reference": "f25a0153d645e234f9db42e5433b16d9b113920f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/1cf4c0b68b8461cea27411ff961482ce7687e34f", - "reference": "1cf4c0b68b8461cea27411ff961482ce7687e34f", + "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/f25a0153d645e234f9db42e5433b16d9b113920f", + "reference": "f25a0153d645e234f9db42e5433b16d9b113920f", "shasum": "" }, "require": { @@ -889,9 +889,9 @@ "description": "Shim to allow support of different psr/message versions.", "support": { "issues": "https://github.com/mpdf/psr-http-message-shim/issues", - "source": "https://github.com/mpdf/psr-http-message-shim/tree/2.0.0" + "source": "https://github.com/mpdf/psr-http-message-shim/tree/v2.0.1" }, - "time": "2023-09-01T06:08:18+00:00" + "time": "2023-10-02T14:34:03+00:00" }, { "name": "mpdf/psr-log-aware-trait", @@ -3308,16 +3308,16 @@ }, { "name": "setasign/fpdi", - "version": "v2.5.0", + "version": "v2.6.0", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4" + "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/ecf0459643ec963febfb9a5d529dcd93656006a4", - "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6db878129ec6c7e141316ee71872923e7f1b7ad", + "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad", "shasum": "" }, "require": { @@ -3329,8 +3329,8 @@ }, "require-dev": { "phpunit/phpunit": "~5.7", - "setasign/fpdf": "~1.8", - "setasign/tfpdf": "~1.31", + "setasign/fpdf": "~1.8.6", + "setasign/tfpdf": "~1.33", "squizlabs/php_codesniffer": "^3.5", "tecnickcom/tcpdf": "~6.2" }, @@ -3368,7 +3368,7 @@ ], "support": { "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.5.0" + "source": "https://github.com/Setasign/FPDI/tree/v2.6.0" }, "funding": [ { @@ -3376,7 +3376,7 @@ "type": "tidelift" } ], - "time": "2023-09-28T10:46:27+00:00" + "time": "2023-12-11T16:03:32+00:00" }, { "name": "symfony/config", diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 7bb462acfe..6105dc4e25 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -12,5 +12,6 @@ - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) - Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) +- Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) ### BC Breaks From a3020196f31dc910d4470d353391a8a7d942f062 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:49:37 +0000 Subject: [PATCH 12/24] Bump phpmd/phpmd from 2.14.1 to 2.15.0 Bumps [phpmd/phpmd](https://github.com/phpmd/phpmd) from 2.14.1 to 2.15.0. - [Release notes](https://github.com/phpmd/phpmd/releases) - [Changelog](https://github.com/phpmd/phpmd/blob/master/CHANGELOG) - [Commits](https://github.com/phpmd/phpmd/compare/2.14.1...2.15.0) --- updated-dependencies: - dependency-name: phpmd/phpmd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- composer.lock | 59 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/composer.lock b/composer.lock index a281bac14b..6f7395a174 100644 --- a/composer.lock +++ b/composer.lock @@ -1104,28 +1104,28 @@ }, { "name": "pdepend/pdepend", - "version": "2.15.1", + "version": "2.16.2", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0" + "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/d12f25bcdfb7754bea458a4a5cb159d55e9950d0", - "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58", + "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58", "shasum": "" }, "require": { "php": ">=5.3.7", - "symfony/config": "^2.3.0|^3|^4|^5|^6.0", - "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0", - "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0" + "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.19" }, "require-dev": { "easy-doc/easy-doc": "0.0.0|^1.2.3", "gregwar/rst": "^1.0", - "phpunit/phpunit": "^4.8.36|^5.7.27", "squizlabs/php_codesniffer": "^2.0.0" }, "bin": [ @@ -1155,7 +1155,7 @@ ], "support": { "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.15.1" + "source": "https://github.com/pdepend/pdepend/tree/2.16.2" }, "funding": [ { @@ -1163,7 +1163,7 @@ "type": "tidelift" } ], - "time": "2023-09-28T12:00:56+00:00" + "time": "2023-12-17T18:09:59+00:00" }, { "name": "phar-io/manifest", @@ -1421,22 +1421,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.14.1", + "version": "2.15.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8" + "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/442fc2c34edcd5198b442d8647c7f0aec3afabe8", - "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0", + "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", "ext-xml": "*", - "pdepend/pdepend": "^2.15.1", + "pdepend/pdepend": "^2.16.1", "php": ">=5.3.9" }, "require-dev": { @@ -1445,7 +1445,6 @@ "ext-simplexml": "*", "gregwar/rst": "^1.0", "mikey179/vfsstream": "^1.6.8", - "phpunit/phpunit": "^4.8.36 || ^5.7.27", "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" }, "bin": [ @@ -1493,7 +1492,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.14.1" + "source": "https://github.com/phpmd/phpmd/tree/2.15.0" }, "funding": [ { @@ -1501,7 +1500,7 @@ "type": "tidelift" } ], - "time": "2023-09-28T13:07:44+00:00" + "time": "2023-12-11T08:22:20+00:00" }, { "name": "phpstan/phpstan", @@ -3380,16 +3379,16 @@ }, { "name": "symfony/config", - "version": "v5.4.26", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650" + "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8109892f27beed9252bd1f1c1880aeb4ad842650", - "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650", + "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", + "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", "shasum": "" }, "require": { @@ -3439,7 +3438,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.26" + "source": "https://github.com/symfony/config/tree/v5.4.31" }, "funding": [ { @@ -3455,7 +3454,7 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:21:11+00:00" + "time": "2023-11-09T08:22:43+00:00" }, { "name": "symfony/console", @@ -3557,16 +3556,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.4.29", + "version": "v5.4.34", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05" + "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/338638ed8c9d5c7fcb136a73f5c7043465ae2f05", - "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/75d568165a65fa7d8124869ec7c3a90424352e6c", + "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c", "shasum": "" }, "require": { @@ -3626,7 +3625,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.29" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.34" }, "funding": [ { @@ -3642,7 +3641,7 @@ "type": "tidelift" } ], - "time": "2023-09-20T06:23:43+00:00" + "time": "2023-12-28T09:31:38+00:00" }, { "name": "symfony/deprecation-contracts", From c73d1ce25647b416fa0ccdd2f7f6c30204d09d58 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 6 Jan 2024 18:06:47 +0100 Subject: [PATCH 13/24] Updated Changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 6105dc4e25..d5565c76f7 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -13,5 +13,6 @@ - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) - Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) - Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) +- Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) ### BC Breaks From 7f110d0944e11513e30b18b4757a2fdbe7b863c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:26:14 +0000 Subject: [PATCH 14/24] Bump phpunit/phpunit from 9.6.14 to 9.6.15 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.14 to 9.6.15. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.15/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.14...9.6.15) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 66 +++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/composer.lock b/composer.lock index 6f7395a174..6ce71d2a3f 100644 --- a/composer.lock +++ b/composer.lock @@ -998,16 +998,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -1048,9 +1048,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "paragonie/random_compat", @@ -1618,23 +1618,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1684,7 +1684,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" }, "funding": [ { @@ -1692,7 +1692,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2023-12-22T06:47:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1937,16 +1937,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.14", + "version": "9.6.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0" + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", - "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", "shasum": "" }, "require": { @@ -2020,7 +2020,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" }, "funding": [ { @@ -2036,7 +2036,7 @@ "type": "tidelift" } ], - "time": "2023-12-01T06:10:48+00:00" + "time": "2023-12-01T16:55:19+00:00" }, { "name": "psr/cache", @@ -2584,20 +2584,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2629,7 +2629,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -2637,7 +2637,7 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", @@ -2911,20 +2911,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2956,7 +2956,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -2964,7 +2964,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", From aa478ac1ce075f469c085b92f4650d2bd1349a5a Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 6 Jan 2024 18:27:50 +0100 Subject: [PATCH 15/24] Updated Changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index d5565c76f7..2aaabc5987 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -14,5 +14,6 @@ - Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) - Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) +- Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) ### BC Breaks From 41b71eda4790d55bbad62bd34cb53eacf3576009 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:49:26 +0000 Subject: [PATCH 16/24] Bump symfony/process from 5.4.28 to 5.4.34 Bumps [symfony/process](https://github.com/symfony/process) from 5.4.28 to 5.4.34. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/7.0/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v5.4.28...v5.4.34) --- updated-dependencies: - dependency-name: symfony/process dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 6ce71d2a3f..6eb3324ccb 100644 --- a/composer.lock +++ b/composer.lock @@ -4643,16 +4643,16 @@ }, { "name": "symfony/process", - "version": "v5.4.28", + "version": "v5.4.34", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b" + "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", - "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", + "url": "https://api.github.com/repos/symfony/process/zipball/8fa22178dfc368911dbd513b431cd9b06f9afe7a", + "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a", "shasum": "" }, "require": { @@ -4685,7 +4685,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.28" + "source": "https://github.com/symfony/process/tree/v5.4.34" }, "funding": [ { @@ -4701,7 +4701,7 @@ "type": "tidelift" } ], - "time": "2023-08-07T10:36:04+00:00" + "time": "2023-12-02T08:41:43+00:00" }, { "name": "symfony/service-contracts", From be41bb67f77ea2f94c7139546545611a2afaf97c Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 6 Jan 2024 18:47:38 +0100 Subject: [PATCH 17/24] Updated Changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 2aaabc5987..2ee54698cc 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -15,5 +15,6 @@ - Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) - Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) +- Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) ### BC Breaks From a0569140aabe24e64e94a5d27713cc9eaa0d4949 Mon Sep 17 00:00:00 2001 From: Gordon Franke Date: Thu, 7 Dec 2023 08:52:02 +0100 Subject: [PATCH 18/24] bug: TemplateProcessor fix multiline values --- docs/changes/2.x/2.0.0.md | 2 ++ src/PhpWord/TemplateProcessor.php | 17 +++++++++++++++++ tests/PhpWordTests/TemplateProcessorTest.php | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 2ee54698cc..a8c3cd596e 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -8,6 +8,8 @@ - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) +- bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) + ### Miscellaneous - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 1ad901d480..27577499e5 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -357,6 +357,15 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ $replace = $xmlEscaper->escape($replace); } + // convert carriage returns + if (is_array($replace)) { + foreach ($replace as &$item) { + $item = $this->replaceCarriageReturns($item); + } + } else { + $replace = $this->replaceCarriageReturns($replace); + } + $this->tempDocumentHeaders = $this->setValueForPart($search, $replace, $this->tempDocumentHeaders, $limit); $this->tempDocumentMainPart = $this->setValueForPart($search, $replace, $this->tempDocumentMainPart, $limit); $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); @@ -1305,6 +1314,14 @@ protected function indexClonedVariables($count, $xmlBlock) return $results; } + /** + * Replace carriage returns with xml. + */ + public function replaceCarriageReturns(string $string): string + { + return str_replace(["\r\n", "\r", "\n"], '', $string); + } + /** * Replaces variables with values from array, array keys are the variable names. * diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index f2d2cfbf13..65d5cfe9d8 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -591,6 +591,24 @@ public function testSetValues(): void self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart()); } + /** + * @covers ::setValues + */ + public function testSetValuesMultiLine(): void + { + $mainPart = ' + + + Address: ${address} + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setValues(['address' => "Peter Pan\nNeverland"]); + + self::assertStringContainsString('Address: Peter PanNeverland', $templateProcessor->getMainPart()); + } + /** * @covers ::setValues */ From 9bf816b084b77b9ff473316d682fc35bf21ceed7 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 7 Jan 2024 12:27:24 -0800 Subject: [PATCH 19/24] Allow `rgb()` When Converting Html (#2512) * Allow `rgb()` When Converting Html Fix #2508. Program currently expects `#xxxxxx` to specify a color when used by the `bgcolor` html attribute or the `color` or `background-color` css attributes. This PR allows support for `rgb(red, green, blue)` as well. * Update Change Log 2.0.0 --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Shared/Html.php | 17 ++++++-- .../Writer/Word2007/Style/FontTest.php | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index a8c3cd596e..c679317049 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -18,5 +18,6 @@ - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) - Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) - Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) +- Allow rgb() when converting Html [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) ### BC Breaks diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 0a9b23979c..2022f7da09 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -37,6 +37,8 @@ */ class Html { + private const RGB_REGEXP = '/^\s*rgb\s*[(]\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*[)]\s*$/'; + protected static $listIndex = 0; protected static $xpath; @@ -142,7 +144,7 @@ protected static function parseInlineStyle($node, $styles = []) break; case 'bgcolor': // tables, rows, cells e.g. - $styles['bgColor'] = trim($val, '# '); + $styles['bgColor'] = self::convertRgb($val); break; case 'valign': @@ -720,11 +722,11 @@ protected static function parseStyleDeclarations(array $selectors, array $styles break; case 'color': - $styles['color'] = trim($value, '#'); + $styles['color'] = self::convertRgb($value); break; case 'background-color': - $styles['bgColor'] = trim($value, '#'); + $styles['bgColor'] = self::convertRgb($value); break; case 'line-height': @@ -1170,4 +1172,13 @@ protected static function parseHorizRule($node, $element): void // - line - that is a shape, has different behaviour // - repeated text, e.g. underline "_", because of unpredictable line wrapping } + + private static function convertRgb(string $rgb): string + { + if (preg_match(self::RGB_REGEXP, $rgb, $matches) === 1) { + return sprintf('%02X%02X%02X', $matches[1], $matches[2], $matches[3]); + } + + return trim($rgb, '# '); + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php index 2c10b5ff2f..a8214ec35b 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007\Style; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWordTests\TestHelperDOCX; /** @@ -155,4 +157,44 @@ public function testPosition(): void self::assertTrue($doc->elementExists($path)); self::assertEquals(-20, $doc->getElementAttribute($path, 'w:val')); } + + public static function testRgb(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(['pageNumberingStart' => 1]); + $html = implode( + "\n", + [ + '', + '', + '', + '', + '', + '', + '', + '
This one is in color.This one too.
', + ] + ); + + Html::addHtml($section, $html, false, false); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $element = '/w:document/w:body/w:tbl/w:tr/w:tc/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + self::assertTrue($doc->elementExists($txtelem)); + self::assertSame('This one is in color.', $doc->getElement($txtelem)->textContent); + self::assertTrue($doc->elementExists($styelem)); + self::assertTrue($doc->elementExists($styelem . '/w:color')); + self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val')); + + $element = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + self::assertTrue($doc->elementExists($txtelem)); + self::assertSame('This one too.', $doc->getElement($txtelem)->textContent); + self::assertTrue($doc->elementExists($styelem)); + self::assertTrue($doc->elementExists($styelem . '/w:color')); + self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val')); + } } From 98d038e05d2c9c0bf483a0c22118438a69853c49 Mon Sep 17 00:00:00 2001 From: Marin Nikolli <34999323+sibalonat@users.noreply.github.com> Date: Mon, 8 Jan 2024 07:34:35 +0100 Subject: [PATCH 20/24] Added extractVariables method to IOFactory (#2515) * Added extractVariables method to IOFactory * remove var_dumps * remove vardump * fix return and fix php stan errors and instances * fix order and whitespace * extra space * remove new lines * white space * new lines * whiteline * new line * white space * fix * new line * white space * remove some unneecessary if statement * Correct Font Size Calculated by MsDoc Reader Fix #2526. Most of that issue has already been fixed. The one remaining problem was a deprecation message handling font size. The code used `dechex($operand / 2)`, and issued the deprecation message whenever `$operand` was odd because `dechex` is designed only for integer conversion. `$operand` is actually 2 times the point size, so it will be odd only when the point size is some integer plus half a point (no other fractions are allowed). At any rate, it seems that `dechex` should not be used here in the first place; font size is a numeric value, not a hex string. There are many problems with MsDoc Reader at the moment. This PR is narrowly focused on the problem at hand. Its test is, at least, more detailed than the existing MsDoc Reader test, which does nothing more than confirm that read successfully creates a PhpWord object. The new test verifies that the font size is as expected, but does not validate any other aspect of the read. * Suggestions from @Progi1984 * Typo Tolerated By Windows but Not By Unix * Correct Title Line of Change Log * Bump dompdf/dompdf from 2.0.3 to 2.0.4 Bumps [dompdf/dompdf](https://github.com/dompdf/dompdf) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/dompdf/dompdf/releases) - [Commits](https://github.com/dompdf/dompdf/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: dompdf/dompdf dependency-type: direct:development ... Signed-off-by: dependabot[bot] * Bump phpunit/phpunit from 9.6.13 to 9.6.14 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.13 to 9.6.14. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.14/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.13...9.6.14) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump mpdf/mpdf from 8.2.0 to 8.2.2 Bumps [mpdf/mpdf](https://github.com/mpdf/mpdf) from 8.2.0 to 8.2.2. - [Release notes](https://github.com/mpdf/mpdf/releases) - [Changelog](https://github.com/mpdf/mpdf/blob/development/CHANGELOG.md) - [Commits](https://github.com/mpdf/mpdf/compare/v8.2.0...v8.2.2) --- updated-dependencies: - dependency-name: mpdf/mpdf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump phpmd/phpmd from 2.14.1 to 2.15.0 Bumps [phpmd/phpmd](https://github.com/phpmd/phpmd) from 2.14.1 to 2.15.0. - [Release notes](https://github.com/phpmd/phpmd/releases) - [Changelog](https://github.com/phpmd/phpmd/blob/master/CHANGELOG) - [Commits](https://github.com/phpmd/phpmd/compare/2.14.1...2.15.0) --- updated-dependencies: - dependency-name: phpmd/phpmd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Updated Changelog * Bump phpunit/phpunit from 9.6.14 to 9.6.15 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.14 to 9.6.15. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.15/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.14...9.6.15) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Updated Changelog * Bump symfony/process from 5.4.28 to 5.4.34 Bumps [symfony/process](https://github.com/symfony/process) from 5.4.28 to 5.4.34. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/7.0/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v5.4.28...v5.4.34) --- updated-dependencies: - dependency-name: symfony/process dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Updated Changelog * Added extractVariables method to IOFactory * remove var_dumps * fix return and fix php stan errors and instances * fix order and whitespace * remove new lines * white space * new lines * whiteline * new line * white space * fix * white space * remove some unneecessary if statement * variable changes * 2.0.0 md * 2.0.0 * new line at end of the file * add entry to md * additional space, type fixes in enhancement md and iofactory * some fixes on spacing * based on fixer suggestions * new line at the end of the file --------- Signed-off-by: dependabot[bot] Co-authored-by: oleibman <10341515+oleibman@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 --- docs/changes/2.x/2.0.0.md | 2 + ..._44_ExtractVariablesFromReaderWord2007.php | 14 +++++++ ...44_ExtractVariablesFromReaderWord2007.docx | Bin 0 -> 12981 bytes src/PhpWord/IOFactory.php | 39 ++++++++++++++++++ tests/PhpWordTests/IOFactoryTest.php | 13 ++++++ .../_files/templates/extract-variable.docx | Bin 0 -> 12575 bytes 6 files changed, 68 insertions(+) create mode 100644 samples/Sample_44_ExtractVariablesFromReaderWord2007.php create mode 100644 samples/resources/Sample_44_ExtractVariablesFromReaderWord2007.docx create mode 100644 tests/PhpWordTests/_files/templates/extract-variable.docx diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index c679317049..74f2184155 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -4,6 +4,8 @@ ## Enhancements +- IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) + ### Bug fixes - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) diff --git a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php new file mode 100644 index 0000000000..24574e5fb7 --- /dev/null +++ b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php @@ -0,0 +1,14 @@ +9(1d|z* z_F-_mz}24O2U?%o(ZLl}!Q$X;NGaHER@v10116W!ZQxMr+$avQ1(N*|^enmP7UzF3 z_?qBSZX`0V3J-C9wqb8=!xyghWY72*oV>0xxmSxrcr{6VCsP||CdS|7|4i}!u>Jkzrtc3YctDT|C2Y4U&C*p7|ZcePKcLaJg_{Ob^~>I%rzY zyWu;yLYyZgnzi~H_V}5)!WXZB>A&s6TPpKu{?&4P&;S6`*O%gE?_|PcVsHG>_BC$( z7O;M%O520DQ3g&BF8OdofMI&|6bMxaT=g|P7|fiy20%n{X)$pnVoN@|$&+?b%{L&a zn(7)0XA9)G+fuME$RV=`!eg~q18oL3vy}D zGf3`Cv-H8Z-=_;sMII0^XBh?wC;B#Zl2w+%jmCVZgyckL8G3BY3$3b4=BGUZT6t}G z);2H^B?bMgerX#jr$_D^x0Pg_5OGMFY8`iQr9pz8hOhRpM8{87y{K;jvFLtM$u{$% z!8gFZk$%#wzj-vxJ9Obj4Jct~Zgglh+lC9Ew!v!ukPhLv5)D-V?#|GOk`N8mVH8Nw z(=Qv0hkTTZhiUFh8!U=%xDx&G=S&*J=kSl2+2Uuky0*p<>{4;15GyD{9&$)l%h3cD ziBv%8Kt7r|57B&J{tB0=tu-T#dF5~*uZ+_buQ{PoqG+8lce8wB>>dk546%SG%0}BJ z zqAq{5S?>F+$zLA!M%c$z{CJ3?lPGmXaerE*hqVhC5N1Bzg|HVy@`Vw`u3GcWXx6QD zz27imzOav}b1jNs#-2*dBp#;P>&ExY9R2ziWc^70xo>?RdK2k(4T_ zG~!4>`+3C(vn57){bj?|*2Xs}=UAJXU?-nWiKm;HCPfUjiDa(ehO%_YG5%>CXP2Mx zC|gq4?Z7t^DJua3ak%4!1ZqvGT@{Vm|7t39#?rnIIX(o)4141-PmpFGzK+!TMpS5- z>O;1-NYGDGE@yA&uuyVYr4@FfpgDhzqsVe(31xpHqdAVKB$Q@5a%)}A@WRT$NKexb z(0Yru?Mn286U?>3ngV=Sw{qzZ3W>H&q^j-9r&`(uc_&Odx1HV z8pX?3>t}iO1aASbV845Te}&4w`htIlO|aJt_SKvG-@eM@M_$9mYX%qe9FXe6z~`eN z^20`o1T^;q5GNEWp@$p0+~@#)kUX3)Xg+nSNOk`HnG^KAE8Hz|#;f?tpcBeoB+zS~ z*8M9X@K_kdTHX4PfEFjtKwD4GCVRq4PI~6bPb`mHX@VuBF42VdExW1U7ip%bn1CJj zel=)Yy^j%2NxN>Wa<~fF%zYJVC~j9Ap;m~uMD_ORtLp(=_7J>+$|OP#FOj4B+)^3@ z+9ps5%+g}9yW(on;S)p=#;nB(^rfBoeP25bv&%YktFxyWpX-VGPbyQL8#SkL&!Xwt z8qi~M_NYnZ1wHTnan&?Dd6g_f0|3Ls008FeV)%X4xLBClnlk+^S$>Znn$i*Y?@`)e z&WVDXMm)#%sx+(%;(p9m*tS*&#Iz|{7k$gNoLpI|V-7aRae{-)j1@&}qCgQrWa<48 zFZyZNUv~2`RORMFy5(2QjyZ$w3WM1gU};B1X$9k0W`_e)(Kzake`UdT^7kYi7%EXt zQpp7;d!+lI;6vE3c+@=lE(W*gATPt4Y5DPd0^AK8KH{8Ef*B_=nqt1bJe+Q3wA}>^ zDrPP-ehIW@e)?!`Ug$O!1~sWdEfxuK$1KRcFRmz0cVyHpf`kbqu5KwyUKr05N+o_I z+b~jGdZ9lm^CdNX!kS>I-J(%!n<^(l3ErFv?DJy4!J#uW6uc~N9^Y+Bg$^@R^E9ZJxlnvTv7`06b*FVj65^^ENbh1RLZ;PKM@| zE4wG>+dk$*bInL87rIy24q*iG0 zMDheAmm#2Pz_y)wEK7b$`DxL~)nO78zbK~jWYRE|lXiLE9^;k|z+#tF67BtXv3q3j zX9N_AkW6kb@<`&-B5FhMVCf{K4wayngRTAKYwD#gYN{+`q`v;x&8<)pD&<8d;Ab^1 z7>~2ZyP+O)syDuT9+!JRHkcynxV9N{$wx=p?l;POv%QZWpAK(;gub=|5&X~F-}PG` zpJHB=n2@yA_8+wk*T+iB0npp2AS8E3*Lh-Zl(RH)to2!H&d(2#lgL|h0=lZ! z+uxX_MIJW2lLuDB_6F-+D|fb6ZQvc{ZD<2v@!9Pa9C+Xz{R{JV79foy76?QTTaFV* z%>APZokO?@#L6jgV@1i*S#zbyp*u!xA-mRsZLjV52qbI|T5bo$x)m zpARx-K%#~htBsR~oiB_Sfs=%1;>&1BGG7Fi2;PEGXs`HW81$?Fg+L9&NQ)3+W222n z9}LX02Y3j`Y?N1bs^W}5nHu@|YzR>kt39cC#_Zh-O&=G7&6Rt0aQEp@O_HP+%rfW( zBUNYRD?6hZ?dYQ^x?vX~-c~bsU+-FnnMcRtoY|%WWk+N8yHv5Yw~~;lBxosg2( z%t;TpEvwR0?Q95_Mv?mJ@~9|>tm(egEe*Ul)V)!`VQTj>>dKaDGlprGFRWomE1%~A zIUK6WcHV}1KZ?s@kHzET9HSy!mKX7qSw7!zjMZOws|{tUvYIDF>i&RGVbwg#BLZU} zy0l<8n=2MH7TNd9RBokmStMKk8FSBE!lz|%6>Etn>|B-Uhrlys8^U&n8#gH&SX3#a z2}B7GI#A$Nru^bC)uXmza^57HV>3L}Y^i3{Ej z%YS{GYAHV6x9w+d(5O{%v{0aE?+vS8 zMqZtaZ(($uY0T}cN;HEwS-Ty*L50q~MYD%at4xAN$>2tf9sDU}lyzIgH7-;sHCyV2 z2tBMxR1&c&+YLgN)oxo#_vnm_VxHc|J9%2)gKFyx=goFQUjC{fW1laD z*?C=&_aoQD45&Nw)S%y@lBmzUMa@Py9u2qNw{paYx?xyE6?ehQ?Td<+-=WcIP4f=V?DE0}vbQU*B zL^(*G;VsmNdb}m&ME=N6CwX2rIj!TT__b^Qa3TyTqz?7dQoXMer=VF8&`sHPwm#!W zz9bj}4BS3bA>EcYLf8A=XPbI4_N}ckDTUWfBoPrZ^IhT$<@&2Bbp0a_wQ{b|R;wRj zHFiFIo3dBS$kNKyw7o&lYnY~H56~)}_y%=l*MWZhaARN>JqC@OpYQ)MN`Pw%@ncHmCk1Ji4;`|l*mp928&f&>5_5dX53ayE5w zv9vRH{w);Ns;}8^aUy;qs(c|iy_i~vKH}{!4A}{pCrn>)7-BZCul`0ZLNOBiqoB#~ z<$-!Je0r9z)@@HzJB;WqE>BYG>GUjYvI`7B(w*mHE8RTqI_oYJjhpgrj4W?tmY+%q zJ<2vkHZK)@Rt%TW%jHJuhjNUPAuxqRR>QlQMLJcA{J7DZR1%LqIvw!FZGRFd?J9g0 za>7HaRA)63aaNHq-YD<+sLbSG`7EtONof`na%`RRZ&Q?TYj%>+AfY*t)_!~A>UEDX zhp&+Xah(`O>xIh+Qd*qXZ8m^ohM^7Z5N>9xtLW^9@GZh7>TxU}oIJjY|E`AA?Yqb& zfaD?%vK~s7kG|i@b!agBsK9(VBiWlZiS-WRP^ZUB&gjN%9KUUfH#DpL=vf{gQZ$(E z+YK0DO>)DZGBmt1=Hu$c;g90@)#J>1?Gb4Cr?WIt$RzcZIgl>jvHFQkC)f^E@;9v| z>3oS4;a1> zD3DioC#HubC`Wc~u`I&%8mMW6RneSc&8pZc)T_0E7ee?4=(Z$4OVn+;6@b%>)+$*WQl{w5q7{$8xNO!n zzndFVfec1t`7mE2*{}&US6l|=@#HoOO^Np%dgU;*2LrpH6aOh~?m)~DK14GCcw0{| zIIDzez@B#N2iuMb_<_ss8{EB=NtbC#&rrtbvv z^VAiFL+gs6{O*Q>>EO|xpkGocB#e9S+3LsYlj&H<-BNN!bjjCDZ|)9`F~!*KP*Glb z$mrvS3N2fJcZ7mtFyg)(;(kF)$n=0BbiQK=l*Q4Lr*vdO3$cs6CYeP0|NLK=)9s8JnLNnw+^PVJf^I&xP6`!W*GLS}8DtftHI z{!R6+!&2cGa8=pYlN2UcEor4vnC^0&xy2=|B!?KCcONyq1z{7483hK!gon}0MR+R$3L!(@SsO$zkTZvMd$bRB0S~_MGW*9I0@kQPdc%>Z1uTgt@fYsYdlYL zmOKHscl7_!Q`wz(k_WtcDHb;X;LX1icV`z58`IzYRBM*DGpHGLV2yA3q;pdFVSUhz zDtjx_F|+Y{#?_m&I89K5+$5J0E(u$IyqF0Pk5)iI&DeM)ZKSwF1orb8TSL$H;fW(G zz&v|fq{uwK?M+Mm=i=N*v3qyU`#XoG3rCC}P|{>rBZ)attL}pLPZ#`dW(`|g<`&e@fZ0XnBDK0FDU-SAf|UT>-By=bxda%Hf}QIt_5Hf>uw zTD9tH)e|S{zX7yq+8ItN6 zT_b~0qZ(2=^Uw*FjL$HzQk%9nSU*c`Vy?r&EWmu;itX6MA+qk*&|G?py1_jl9UV#^ zt#3^Kju3P5t@xsS|HpD$&8{8#9FSPF^~@yNP4XU#RQL4ZfQp$79$oyo=a;wGIF--p zSNbpJ&p&`>Eyvw^HB%zwJwWgN;l{zMfuDk9LUTEzzA3B>=j+>v+qo#_`S>i`X>dyh z-E1uQUxC~s5f?g@HIpl1o>4S8co`xQax5&J70`K%yDO@nZY*C*If~; zJKMeTp)@HvA6eX+F816Cq}r4cLzVwVROF0$reBIH9PKNvw?|(X{kgkei3| zIQn7_WIc%8kIPg{BRx}bQY&2Us~bK$9(Cu7zn~{DVSDX7?y`h*&52rcN8Q_AKlp96 zo^2$mJwrd&)#X%=kJlSWK+rZH9ld7#p6aA7Kjx&4Ea1-f_(MV5@afKt1J~!~s4WGu z^eq(p^sNcB^sQL<^eqMO^etEy_5suZi)b<#)J&1!3hG+_r%u$PmE|MnKq9w?#Pxv{ zL5N$&1}bl%r$$gs1Cg6ob-#02p_;=tlVq#_RnCO!52jrK{vF80RVr1b zro3?S@}B%;`{ZCn!!}o9{Ha*17am@LIC1yicY_%B!FdqOHmg+n2G)ZwF4G2_x*)K` zn^SWk%v!10210LpUHZ-Ww=4%~ATp5gA`)RN(`4X`oVy5zH29-JLx3dl(hDtzdf#eTemE_RG?wda&WB^^!PCRX89klqGzeCQhGuJJuJo4R z5aWolD6qnt{5;E^=UBFxV72_(X#Bll*)wn?j8P?dc3o-=e5q=Q&^V}p2>`L6#?UAu zeBPLr^%-SvG{^NCT`(ft>-m19(ei!a$vbXR`}7@4F@vPap(i>icIiARL&%#wyeKIh zX~MYHWPVaV29F*J*RtdxPd`_2@sM{lCf35y$$-J-BU*)}l zO5mtuQXS5reg4o-(MJBlpgF3^DD$m0cu#1SYn}kI!G@(#^o9kUCTgwyh+L)@Yz2Pv zVB?z7Jr+UN?7%M<>{FaL2|BBp5BaHm$L-|_I}*RTxWm1~49GdJM-M|mX+@k2DC4-E#(%Cd&quP zZYbWQFqX$Y(qojpZod6@fzG>@?zQCn*Jv0crha_;0(G- zHX~i`sdz_>U%!oZ{`vX2Zry3lRtH;@VMI@^I;#1hIgFCQy*d_mWHmH)&FFa$7CBa} z_CaR+Qh=EC8{;PBy947HmJOqpZbhCu?3{QG*&1q)xPw??Usa;mz?>R-bd^qrt8K<& zPbO8*$lgP0kT>I2sCl$tldWnSzh-5npv)V&n=9U*9%O{O;>>AGG1s8ft(9-dvR&sMQAgV2>wL9LY_1MP;UAZfF{Q0;CzjIr>C`;e+*M|Z{Xtt#0PMV7Q|x9q(>Jl2 z*RI30`|FFW?!47T;ts#X_S;J#$GT+G<*fz2l}6OIi)j2wKCmX#HrBZ5w@LBKiK|UR zQF~bh%djr>{%qik+QMEs_5Rm_i||U`)w7>fKjTk&@vKXH34%wp$VJwmX+)*Y1$So3 z6@k|(LGi<)6??sdZNQx?;+3h8+ZLlh()Ye3*8gAquLu#y-ybX8U0Ss~rcn7HjDSfx zArb^zt1#y2_*o%WK(1tB^%b#6_SbtP;0!9E?_M8O5P{m!6A8koRrsT;u6cGszhr`t zO2y*j6>^43Tkx-`{V~w*^ZD;7TFGG{qtMn4z+o;uz+x(S2g1|*XKw$3{MM8z>0Fln zbN0GtnmKtcx@H|ALI?Y;MjbC-%bFF1erh+_&ItReOw)3ey|lsV7kI;K+4J)=Ur7js zruK`Zi_Sz(A8^j=p!xBh-96p5{tlwV~`}(tIYmu7eyJE zB^%6oEF}5ZN;4x7x>D%okL=`Oa1elPRj?c5p74yeRM(jzhcwc?*A8|FY+lUKmo@mYlrgkDm!ChKFSV!I7bd~ zwaN}-smCrcr!050vf>)MG~@F}4s!Pkm73I+k$@dqeduh)Lu=JRVt#%d$X;DkC8cakF_A+(pWh~J3(GK>#7?9h(Q#;z z^|BqKfXO%MkCgP`O8?CQ`(QDO`$aR1{kOH@n|}wpPDO63n%Hy z6b>E`2nQO<@9T6Leeo_d6@6M7tO+$M&z@>M@3W@`*({gfaDZGz_Zl7bV=Sw)7q^Fp zFqtG@ofStMG9omCqib7it(`Q*KR1yZ*Zfu&Mo9zromYY$mb_9HI6S&%$=Q*!Ri~c! z_*7WG&3B&7t-nk&UFtjg4K!?1nqxL_^>80~vLG`g?|6+=;t`++yg@o}gMz+pd9usE zrhtAiQ`gyJ($?c^^zQp|CD`S;q~n$IWznn+3x(r(#1Z7ub)Yy6TApaNa^P_qQ&5E{ zCMqk^@-U+0dD?jYb?tU=SY(MT%+}o+1xV_i-{$IWaO0xb!DZ@fKK7teA0;n6$N@A} zVM7BFmR0DFEMWQYuGYWLVV>K}`_x26iPp`kE;&5vn2{zT#C(J4(y}BqXSw&X1AM%A z`N#dr<92H~<7>f5`n5cT@$dbLo2ilVUk+C?C&yk1HHd)qhk`cIB))<#ehT6ntg=fU zAc(-;LR3keKEt4f91vJpZ_shPuWxnM)%6eEYos{(V5QNbra@v0cFv#DXIFQenqiUg z@De^p<3%-@yLU=Dskfp2s-_&Rd4is>Ut>~G-$vk+)FbKEU88>Mvq%rc3vDDk z`6K|eX=JHM;TzN@h^v%RX55Kaly|(PKT%(O0*i3$d_>l;;*Mfd!xnY=F;QifS<}ih zhnV?7!3G#4SB_EInQtFvRHIO(D-9uyl(ur*8gD<0o9}xNG*ICiKzs4*CrY_;;BtCe znPJ+P$#J8AZMyqM5i!742^6|e>=KbPLj6we_SZdh^RD=`;9F;6M(VIyME2Up9WnUW(BjY1V7!py25I$g14!K(4 znSTQZ86fvw)9qKS=H%R5J#T>T&Ow>HRh(*Q)19v;4zu(hEU@noig6VIZGy)_{z&X> z_knBjaX&rpdu~lpB5kCYM_=u6TpJHey?z@qfZO}|WQvB|iMbFFg2aBYx9hV{x~!W~ zc=5Y0EW>e)F5dG;3x$YY(eSd$7(K>#- z$GMp(s@#~c7)JNazbucVKO~#AX(VQ0! zOOrD%42Vx3cg^?;cPd7n78kDX_;E&y_#L#nntGsF2E3Y6iUv!!J0ag`3Tp7-nx{Kf z+uXsfEguI3r0Bef$c&s6o4wU6&JBgLouZm3Fq%V(YOeYS&RpQChv>*22f-%j`fwda z7bA?ZDBgPr@<}N*T+M`(YBC^6+gqM$a4sj1Xcz?Eo(f@B%WV zKHa2$!-WzFvK*Dz8zO>is5^xooCdhO%IN@=LpC0zqiEM8k)Lgu)lXZ!h}q9h_|TCS z$`ppd4=&puIOzIuGiT<|WUrJLE_yEXr+_Y1P_&Ds|OaSBxUuGX@~%#m6>24zJXX=u2bz>-0QWs{HxP{soY zICp*kIzM8{m(s#fJO@86H3mF8pSv+_bKuFQ{mFl=`zcs@5dQO8jNNlKhS6nVAEiZf4NCN!; zBRh<@yrCmYv^%0!>I=;6hIE~9Bn=vV=KdbR_y#tfq`ah1Cvj%hWmv@A!SEOsC(Hzj z-q)U$!@BeqN&0dWPhFkjhmt>6*5t1HpFRmK6@TNnls|iT+%F{HNN!%lgi+b?H`lv| zAAXzDgVJ=gi|w!`a3dMo1hr!gg7ZN$0*ltR^lnt3LMH4cpxt@o&$OWtUM7<2E1!u= z&S)+*iGIOL$3x&-TyB-oexI{50Od;XIkbCSv!N*AJXw&R(X2$~LwvuD@2;nqyh1cY+fQ$FV8toZsL-g8yPnQ98n@Gkk zd|8~2smGUJ^emM>iJO^5my9^vUB!Y49dd6l+%_75cUYS5ufuoM_i4NB4G$ci9rlF5 zcMa^V*nV&`!uI(b3auoJ#%QY%f-{#%wIU3h@}G)kjf!a#$*bCKw~P$N2j+M>462W8 zQ-qj9s*C!dnhA5#RJ^%Wn_N2V()TQh_PZ=7`SM1MWRR#wlJ52`O455%y6J${=Dgd{ zUb(th6PjDd-u#%4@kEe0pBG$dX`^QNG(TbS=Wj~G&RGP_sNAjW?IqY(HsWVt^*DB2 zpa~z}e96h{%GZI6!g0yz-Di`QK_DQb#>UrFGfnVPV&_AYnE!l^s~F&0_@Ho?VaTHA=}tHr z{A^JPf+@75EMq0|O-Atw7m>Zle9sEg%OF6!B%D3ojCG(q_7Y~8OIVbnlAIDj;j;yu zWmF4uu}1c1777N=@S1V{Gr#{|fBT>EAK3m1(tlU*cQ*2$Pyis|)w=$|P5u@5D^2rH zXw54D=f6mszrz2{@A?xA05rk>0ssH7y?)j7E9d7=T_>*vg@0rK{i@>EI_aM(p3(nM z@z<*9ukc@s7k|P_aQ+SdPbuS9@UJ_GKfxLle}I44SNy8s*IfBe4ULq4X!u*^{44(N zA^%VGYc+-z0Qj#2;8*zHz42e+v-E#~|KXbzq@iAy$8XGc1VGnojload($filename); } + /** + * Loads PhpWord ${variable} from file. + * + * @param string $filename The name of the file + * + * @return array The extracted variables + */ + public static function extractVariables(string $filename, string $readerName = 'Word2007'): array + { + /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ + $reader = self::createReader($readerName); + $document = $reader->load($filename); + $extractedVariables = []; + foreach ($document->getSections() as $section) { + $concatenatedText = ''; + foreach ($section->getElements() as $element) { + if ($element instanceof TextRun) { + foreach ($element->getElements() as $textElement) { + if ($textElement instanceof Text) { + $text = $textElement->getText(); + $concatenatedText .= $text; + } + } + } + } + preg_match_all('/\$\{([^}]+)\}/', $concatenatedText, $matches); + if (!empty($matches[1])) { + foreach ($matches[1] as $match) { + $trimmedMatch = trim($match); + $extractedVariables[] = $trimmedMatch; + } + } + } + + return $extractedVariables; + } + /** * Check if it's a concrete class (not abstract nor interface). * diff --git a/tests/PhpWordTests/IOFactoryTest.php b/tests/PhpWordTests/IOFactoryTest.php index ee8d7fe180..79f0fd0c76 100644 --- a/tests/PhpWordTests/IOFactoryTest.php +++ b/tests/PhpWordTests/IOFactoryTest.php @@ -116,4 +116,17 @@ public function testLoad(): void IOFactory::load($file) ); } + + /** + * Test for extractVariables method. + */ + public function testExtractVariables(): void + { + $file = __DIR__ . '/_files/templates/extract-variable.docx'; + $extractedVariables = IOFactory::extractVariables($file, 'Word2007'); + + $expectedVariables = ['date', 'A1', 'B1']; + + self::assertEquals($expectedVariables, $extractedVariables, 'Extracted variables do not match expected variables.'); + } } diff --git a/tests/PhpWordTests/_files/templates/extract-variable.docx b/tests/PhpWordTests/_files/templates/extract-variable.docx new file mode 100644 index 0000000000000000000000000000000000000000..f95ec61862f7b5bc97a8eb65f5f3ce24407dd88d GIT binary patch literal 12575 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 Date: Mon, 8 Jan 2024 01:25:37 -0800 Subject: [PATCH 21/24] Template Processor Persist File After Destruct (#2545) * Template Processor Persist File After Destruct Replace PR #2542. Fix #2539. Inadvertent break in TemplateProcessor behavior after #2475. Deleted temp file on destruct. It will now persist after destructor. * Update Change Log --- docs/changes/1.x/1.2.0.md | 3 +- docs/changes/2.x/2.0.0.md | 2 +- src/PhpWord/TemplateProcessor.php | 17 ++--- tests/PhpWordTests/TemplateProcessorTest.php | 73 +++++++++++--------- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 265d25b033..7a4b09ea2d 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -64,4 +64,5 @@ ### BC Breaks -- Removed dependency `laminas/laminas-escaper` \ No newline at end of file +- Removed dependency `laminas/laminas-escaper` +- *Unintended Break* TemplateProcessor Does Not Persist File After Destruct. [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) To be fixed by [#2545](https://github.com/PHPOffice/PHPWord/pull/2545 diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 74f2184155..575510b222 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -9,7 +9,7 @@ ### Bug fixes - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) - +- TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 27577499e5..8aee40c546 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -146,18 +146,6 @@ public function __destruct() // Nothing to do here. } } - // Temporary file - if ($this->tempDocumentFilename && file_exists($this->tempDocumentFilename)) { - unlink($this->tempDocumentFilename); - } - } - - public function __wakeup(): void - { - $this->tempDocumentFilename = ''; - $this->zipClass = null; - - throw new Exception('unserialize not permitted for this class'); } /** @@ -1506,4 +1494,9 @@ public function setMacroChars(string $macroOpeningChars, string $macroClosingCha self::$macroOpeningChars = $macroOpeningChars; self::$macroClosingChars = $macroClosingChars; } + + public function getTempDocumentFilename(): string + { + return $this->tempDocumentFilename; + } } diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 65d5cfe9d8..49e88d1b5b 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -21,7 +21,6 @@ use Exception; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Exception\Exception as WordException; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; @@ -38,14 +37,36 @@ */ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase { + /** @var ?TemplateProcessor */ + private $templateProcessor; + + private function getTemplateProcessor(string $filename): TemplateProcessor + { + $this->templateProcessor = new TemplateProcessor($filename); + + return $this->templateProcessor; + } + + protected function tearDown(): void + { + if ($this->templateProcessor !== null) { + $filename = $this->templateProcessor->getTempDocumentFilename(); + $this->templateProcessor = null; + if (file_exists($filename)) { + @unlink($filename); + } + } + } + /** * Construct test. * * @covers ::__construct + * @covers ::__destruct */ public function testTheConstruct(): void { - $object = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); + $object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); self::assertInstanceOf('PhpOffice\\PhpWord\\TemplateProcessor', $object); self::assertEquals([], $object->getVariables()); } @@ -106,7 +127,7 @@ public function xtestTemplateCanBeSavedInTemporaryLocation(string $templateFqfn, public function testXslStyleSheetCanBeApplied(): void { $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx'; - $templateProcessor = new TemplateProcessor($templateFqfn); + $templateProcessor = $this->getTemplateProcessor($templateFqfn); $actualDocumentFqfn = $this->xtestTemplateCanBeSavedInTemporaryLocation($templateFqfn, $templateProcessor); $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx'; @@ -150,7 +171,7 @@ public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue $this->expectExceptionMessage('Could not set values for the given XSL style sheet parameters.'); } - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); $xslDomDocument = new DOMDocument(); $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); @@ -171,7 +192,7 @@ public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplat { $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $this->expectExceptionMessage('Could not load the given XML document.'); - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); $xslDomDocument = new DOMDocument(); $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); @@ -190,7 +211,7 @@ public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplat */ public function testDeleteRow(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); self::assertEquals( ['deleteMe', 'deleteMeToo'], @@ -216,7 +237,7 @@ public function testDeleteRow(): void */ public function testCloneRow(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); self::assertEquals( ['tableHeader', 'userId', 'userName', 'userLocation'], @@ -240,7 +261,7 @@ public function testCloneRow(): void */ public function testCloneRowWithCustomMacro(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); $templateProcessor->setMacroOpeningChars('{#'); $templateProcessor->setMacroClosingChars('#}'); @@ -397,7 +418,7 @@ public function testCloneRowAndSetValuesWithCustomMacro(): void */ public function testMacrosCanBeReplacedInHeaderAndFooter(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); self::assertEquals(['documentContent', 'headerValue:100:100', 'footerValue'], $templateProcessor->getVariables()); @@ -418,7 +439,7 @@ public function testMacrosCanBeReplacedInHeaderAndFooter(): void */ public function testCustomMacrosCanBeReplacedInHeaderAndFooter(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer-with-custom-macro.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer-with-custom-macro.docx'); $templateProcessor->setMacroOpeningChars('{{'); $templateProcessor->setMacroClosingChars('}}'); @@ -440,7 +461,7 @@ public function testCustomMacrosCanBeReplacedInHeaderAndFooter(): void */ public function testSetValue(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); Settings::setOutputEscapingEnabled(true); $helloworld = "hello\nworld"; $templateProcessor->setValue('userName', $helloworld); @@ -455,7 +476,7 @@ public function testSetValue(): void */ public function testSetValueWithCustomMacro(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); $templateProcessor->setMacroChars('{#', '#}'); Settings::setOutputEscapingEnabled(true); $helloworld = "hello\nworld"; @@ -786,7 +807,7 @@ public function testSetCheckboxWithCustomMacro(): void */ public function testSetImageValue(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); $imagePath = __DIR__ . '/_files/images/earth.jpg'; $variablesReplace = [ @@ -866,7 +887,7 @@ public function testSetImageValue(): void */ public function testCloneDeleteBlock(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx'); self::assertEquals( ['DELETEME', '/DELETEME', 'CLONEME', 'blockVariable', '/CLONEME'], @@ -906,7 +927,7 @@ public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresent() $templatePath = 'test.docx'; $objWriter->save($templatePath); - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $variableCount = $templateProcessor->getVariableCount(); unlink($templatePath); @@ -943,7 +964,7 @@ public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresentWi $templatePath = 'test.docx'; $objWriter->save($templatePath); - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $templateProcessor->setMacroChars('{{', '}}'); $variableCount = $templateProcessor->getVariableCount(); unlink($templatePath); @@ -981,7 +1002,7 @@ public function testCloneBlockCanCloneABlockTwice(): void $objWriter->save($templatePath); // replace placeholders and save the file - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $templateProcessor->setValue('title', 'Some title'); $templateProcessor->cloneBlock('subreport', 2); $templateProcessor->setValue('subreport.id', '123', 1); @@ -1034,7 +1055,7 @@ public function testCloneBlockCanCloneABlockTwiceWithCustomMacro(): void $objWriter->save($templatePath); // replace placeholders and save the file - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $templateProcessor->setMacroChars('{{', '}}'); $templateProcessor->setValue('title', 'Some title'); $templateProcessor->cloneBlock('subreport', 2); @@ -1323,7 +1344,7 @@ public function testFixBrokenMacrosWithCustomMacro(): void */ public function testMainPartNameDetection(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); $variables = ['test']; @@ -1335,7 +1356,7 @@ public function testMainPartNameDetection(): void */ public function testMainPartNameDetectionWithCustomMacro(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-with-custom-macro-xml.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-with-custom-macro-xml.docx'); $templateProcessor->setMacroOpeningChars('{#'); $templateProcessor->setMacroClosingChars('#}'); $variables = ['test']; @@ -1595,18 +1616,6 @@ public function testShouldMakeFieldsUpdateOnOpen(): void self::assertStringContainsString('', $templateProcessor->getSettingsPart()); } - /** - * Should not allow unserialize to avoid malware. - */ - public function testUnserialize(): void - { - $this->expectException(WordException::class); - $this->expectExceptionMessage('unserialize not permitted'); - $object = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); - $serialized = serialize($object); - $object2 = unserialize($serialized); - } - public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void { $settingsPart = ' From 2f4da6e491643c88f3c5d2892f5a63febb66b313 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:24:22 -0800 Subject: [PATCH 22/24] Invalid Annotation in Test Member (#2549) * Invalid Annotation in Test Member PhpUnit cannot parse the `@covers` lines in FormulaTest; they result in warnings in Coverage and Deploy tests. This PR fixes them; no change log entry should be needed. * Fluke Failure PhpWordTest ran in such a way that `new PhpWord()` and `new DocInfo()` happened in different seconds. Almost impossible, but easy enough to prevent. --- tests/PhpWordTests/Element/FormulaTest.php | 6 +++--- tests/PhpWordTests/PhpWordTest.php | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/PhpWordTests/Element/FormulaTest.php b/tests/PhpWordTests/Element/FormulaTest.php index fef5c2221e..7e368e8995 100644 --- a/tests/PhpWordTests/Element/FormulaTest.php +++ b/tests/PhpWordTests/Element/FormulaTest.php @@ -30,7 +30,7 @@ class FormulaTest extends AbstractWebServerEmbeddedTest { /** - * @covers \Formula::__construct + * @covers \PhpOffice\PhpWord\Element\Formula::__construct */ public function testConstruct(): void { @@ -40,8 +40,8 @@ public function testConstruct(): void } /** - * @covers \Formula::getMath - * @covers \Formula::setMath + * @covers \PhpOffice\PhpWord\Element\Formula::getMath + * @covers \PhpOffice\PhpWord\Element\Formula::setMath */ public function testMath(): void { diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php index 7b756e7082..33118a11e8 100644 --- a/tests/PhpWordTests/PhpWordTest.php +++ b/tests/PhpWordTests/PhpWordTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests; use BadMethodCallException; +use DateTimeImmutable; use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; @@ -35,8 +36,14 @@ class PhpWordTest extends \PHPUnit\Framework\TestCase */ public function testConstruct(): void { - $phpWord = new PhpWord(); - self::assertEquals(new DocInfo(), $phpWord->getDocInfo()); + do { + $dtStart = new DateTimeImmutable(); + $startSecond = $dtStart->format('s'); + $phpWord = new PhpWord(); + $docInfo = new DocInfo(); + $endSecond = (new DateTimeImmutable('now'))->format('s'); + } while ($startSecond !== $endSecond); + self::assertEquals($docInfo, $phpWord->getDocInfo()); self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); self::assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); } From 8b891bb6842dd383f679b47898fad0b7c181f325 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 23 Jan 2024 09:15:27 -0800 Subject: [PATCH 23/24] Fix 32-bit Problem in PasswordEncoder (#2551) * Fix 32-bit Problem in PasswordEncoder Fix #2550. * Update change log --- docs/changes/2.x/2.0.0.md | 2 ++ src/PhpWord/Shared/Microsoft/PasswordEncoder.php | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 575510b222..8214ded041 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -12,6 +12,8 @@ - TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) +- 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) + ### Miscellaneous - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index 5ff42e49b9..d6cf69fc6d 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -34,6 +34,9 @@ class PasswordEncoder const ALGORITHM_MAC = 'MAC'; const ALGORITHM_HMAC = 'HMAC'; + private const ALL_ONE_BITS = (PHP_INT_SIZE > 4) ? 0xFFFFFFFF : -1; + private const HIGH_ORDER_BIT = (PHP_INT_SIZE > 4) ? 0x80000000 : PHP_INT_MIN; + /** * Mapping between algorithm name and algorithm ID. * @@ -128,7 +131,7 @@ public static function hashPassword($password, $algorithmName = self::ALGORITHM_ // 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); + $hex = str_pad(strtoupper(dechex($combinedKey & self::ALL_ONE_BITS)), 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'); @@ -232,10 +235,10 @@ private static function buildCombinedKey($byteChars) */ private static function int32($value) { - $value = ($value & 0xFFFFFFFF); + $value = $value & self::ALL_ONE_BITS; - if ($value & 0x80000000) { - $value = -((~$value & 0xFFFFFFFF) + 1); + if ($value & self::HIGH_ORDER_BIT) { + $value = -((~$value & self::ALL_ONE_BITS) + 1); } return $value; From 2daa50c6f34c9cb6c532f72350e4bd8d466d6c71 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 15 May 2024 13:26:52 +0200 Subject: [PATCH 24/24] Improved Issue Template (#2609) --- .github/ISSUE_TEMPLATE/1_bug_report.yml | 65 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/2_feature_request.yml | 35 +++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 38 ------------ .github/ISSUE_TEMPLATE/feature_request.md | 22 ------- .github/ISSUE_TEMPLATE/how-to-use.md | 14 ----- .github/PULL_REQUEST_TEMPLATE.md | 7 ++- docs/changes/2.x/2.0.0.md | 3 +- 7 files changed, 106 insertions(+), 78 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/1_bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/2_feature_request.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/how-to-use.md diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.yml b/.github/ISSUE_TEMPLATE/1_bug_report.yml new file mode 100644 index 0000000000..ea335468a5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report.yml @@ -0,0 +1,65 @@ +name: 🐛 Bug Report +description: Create a report to help improve PHPWord +labels: [ "Bug Report" ] +body: + - type: markdown + attributes: + value: | + ### ❗️ Read this before submitting your bug report: + - **Write in English/French.** Reports in all other languages will be closed. + - **Provide as much detail as possible** + - Attachments : Error logs, Screenshots, Document files (generated and expected). + - If the issue cannot be reproduced, it cannot be fixed. + - type: textarea + id: what-happened + attributes: + label: Describe the bug and add attachments + description: What went wrong? If possible, add screenshots, error logs, document files (generated and expected) or screen recordings to help explain your problem. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: A clear and concise description of what you expected to happen. + validations: + required: true + - type: textarea + id: steps-reproduce + attributes: + label: Steps to reproduce + description: Please provide a code sample that reproduces the issue. + placeholder: | + ```php + addSection(); + $section->... + ``` + validations: + required: true + - type: input + id: phpword-version + attributes: + label: PHPWord version(s) where the bug happened + placeholder: "e.g., 1.2.0 or master" + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP version(s) where the bug happened + placeholder: "e.g., 7.1 or 8.2" + validations: + required: true + - type: checkboxes + attributes: + label: Priority + description: Funded tickets have a higher priority. + options: + - label: I want to crowdfund the bug fix (with [@algora-io](https://docs.algora.io/bounties/overview)) and fund a community developer. + required: false + - label: I want to pay the bug fix and fund a maintainer for that. (Contact @Progi1984) + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2_feature_request.yml b/.github/ISSUE_TEMPLATE/2_feature_request.yml new file mode 100644 index 0000000000..bf3539c372 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request.yml @@ -0,0 +1,35 @@ +name: 💡 Feature request +description: Suggest an idea for this project +labels: [ "Change Request" ] +body: + - type: markdown + attributes: + value: | + ### ❗️ Read this before submitting your bug report: + - **Write in English/French.** Reports in all other languages will be closed. + - **Provide as much detail as possible** + - Attachments : Error logs, Screenshots, Document files (generated and expected). + - If the issue cannot be reproduced, it cannot be fixed. + - type: textarea + id: problem + attributes: + label: Describe the problem + description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Describe the expected behavior + description: A clear and concise description of what you expected to happen. If possible, add screenshots, document files (expected). + validations: + required: true + - type: checkboxes + attributes: + label: Priority + description: Funded tickets have a higher priority. + options: + - label: I want to crowdfund the feature (with [@algora-io](https://docs.algora.io/bounties/overview)) and fund a community developer. + required: false + - label: I want to pay the feature and fund a maintainer for that. (Contact @Progi1984) + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index fcb3a65db1..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help improve PHPWord -labels: Bug Report - ---- - -### Describe the Bug - -A clear and concise description of what the bug is. - -### Steps to Reproduce - -Please provide a code sample that reproduces the issue. - -```php -addSection(); -$section->... -``` - -### Expected Behavior - -A clear and concise description of what you expected to happen. - -### Current Behavior - -What is the current behavior? - -### Context - -Please fill in your environment information: - -- PHP Version: -- PHPWord Version: diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 171e8378e1..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -labels: Change Request - ---- - -### Is your feature request related to a problem? Please describe. - -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -### Describe the solution you'd like - -A clear and concise description of what you want to happen. - -### Describe alternatives you've considered - -A clear and concise description of any alternative solutions or features you've considered. - -### Additional context - -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/how-to-use.md b/.github/ISSUE_TEMPLATE/how-to-use.md deleted file mode 100644 index 85cc47072e..0000000000 --- a/.github/ISSUE_TEMPLATE/how-to-use.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: How to Use PHPWord -about: Find out how to use PHPWord -labels: WontFix - ---- - -***Please do not use the issue tracker to ask how to use PHPWord.*** - -Documentation is available on [Read the Docs](https://phpword.readthedocs.io/en/latest/). - -Sample code is in the [`/samples/` directory](https://github.com/PHPOffice/PHPWord/tree/master/samples). - -Usage questions belong on [Stack Overflow](https://stackoverflow.com/questions/tagged/phpword). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5430a996ec..ce201f8bb6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,6 +6,7 @@ Fixes # (issue) ### Checklist: -- [ ] I have run `composer run-script check --timeout=0` and no errors were reported -- [ ] The new code is covered by unit tests (check build/coverage for coverage report) -- [ ] I have updated the documentation to describe the changes +- [ ] My CI is :green_circle: +- [ ] I have covered by unit tests my new code (check build/coverage for coverage report) +- [ ] I have updated the [documentation](https://github.com/PHPOffice/PHPWord/tree/master/docs) to describe the changes +- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/2.x/2.0.0.md) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 8214ded041..c5fbaf4b52 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -22,6 +22,7 @@ - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) - Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) - Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) -- Allow rgb() when converting Html [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) +- Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) +- Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) ### BC Breaks