From ad58e726e53e4eabf124515084c1b9aa1c1cb4e4 Mon Sep 17 00:00:00 2001 From: Bruno Casado Date: Mon, 20 Jan 2014 10:55:54 -0200 Subject: [PATCH 001/326] Add some tests to new wrapping image --- samples/Sample_03_Image.php | 107 +++++++++++++++++++++++++++++++++ samples/assets/img/flowers.jpg | Bin 0 -> 126991 bytes 2 files changed, 107 insertions(+) create mode 100644 samples/Sample_03_Image.php create mode 100644 samples/assets/img/flowers.jpg diff --git a/samples/Sample_03_Image.php b/samples/Sample_03_Image.php new file mode 100644 index 00000000..2d6b8bcd --- /dev/null +++ b/samples/Sample_03_Image.php @@ -0,0 +1,107 @@ +'); +} + +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PHPWord object' , EOL; +$PHPWord = new PHPWord(); + +// Create a new Section +$section = $PHPWord->createSection(); + +// Behind Test +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_BEHIND + ) +); + +// Square Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_SQUARE + ) +); + +// tight Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_TIGHT + ) +); + +// infront Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_INFRONT + ) +); + +// inline Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'align' => "center", + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_INLINE + ) +); + +// Save File +echo date('H:i:s') , ' Write to Word2007 format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + +echo date('H:i:s') , ' Write to OpenDocumentText format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +$objWriter->save(str_replace('.php', '.odt', __FILE__)); + +echo date('H:i:s') , ' Write to RTF format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF'); +$objWriter->save(str_replace('.php', '.rtf', __FILE__)); + + +// Echo memory peak usage +echo date('H:i:s') , ' Peak memory usage: ' , (memory_get_peak_usage(true) / 1024 / 1024) , ' MB' , EOL; + +// Echo done +echo date('H:i:s') , ' Done writing file' , EOL; \ No newline at end of file diff --git a/samples/assets/img/flowers.jpg b/samples/assets/img/flowers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd55c65e0e8ebc037831766083f7349b71b6f603 GIT binary patch literal 126991 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 literal 0 HcmV?d00001 From 833dfea1e00adb8978d5a585fbb2052ade5b029e Mon Sep 17 00:00:00 2001 From: japonicus Date: Tue, 8 Apr 2014 17:42:01 +0100 Subject: [PATCH 002/326] Keep image aspect ratio if only 1 dimension styled If only one of image width or height is specified, then scale missing dimension to maintain the aspect ratio. --- src/PhpWord/Element/Image.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d49972d2..611b36b3 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -131,9 +131,17 @@ class Image extends AbstractElement $this->source = $source; $this->isWatermark = $isWatermark; $this->style = $this->setStyle(new ImageStyle(), $style, true); - if ($this->style->getWidth() == null && $this->style->getHeight() == null) { - $this->style->setWidth($imgData[0]); - $this->style->setHeight($imgData[1]); + $styleWidth = $this->style->getWidth(); + $styleHeight = $this->style->getHeight(); + if (!($styleWidth && $styleHeight)) { + if ($styleWidth == null && $styleHeight == null) { + $this->style->setWidth($imgData[0]); + $this->style->setHeight($imgData[1]); + } else if ($styleWidth) { + $this->style->setHeight($imgData[1] * ($styleWidth / $imgData[0])); + } else { + $this->style->setWidth($imgData[0] * ($styleHeight / $imgData[1])); + } } $this->setImageFunctions(); } From a5b5e0cff015ebcedae807892fd4b7476dc0a4de Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 17:43:03 +0700 Subject: [PATCH 003/326] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a932eda..937930e8 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ This release marked heavy refactorings on internal code structure with the creat - Writer: New 'ODText\Base` class - @ivanlanin GH-187 - General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin - General: Add some unit tests for Shared & Element (100%!) - @Progi1984 +- Test: Add some samples and tests for image wrapping style - @brunocasado GH-59 ## 0.9.1 - 27 Mar 2014 From e78489b36e5d06055c3c18091f362fc7d4a1077f Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 18:03:59 +0700 Subject: [PATCH 004/326] Update unit test and changelog --- CHANGELOG.md | 1 + src/PhpWord/Element/Image.php | 11 ++++++----- tests/PhpWord/Tests/Element/ImageTest.php | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 937930e8..70f53abf 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ This release marked heavy refactorings on internal code structure with the creat - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin +- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 ### Bugfixes diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 139c578f..ce4b1609 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -133,14 +133,15 @@ class Image extends AbstractElement $this->style = $this->setStyle(new ImageStyle(), $style, true); $styleWidth = $this->style->getWidth(); $styleHeight = $this->style->getHeight(); + list($actualWidth, $actualHeight) = $imgData; if (!($styleWidth && $styleHeight)) { if ($styleWidth == null && $styleHeight == null) { - $this->style->setWidth($imgData[0]); - $this->style->setHeight($imgData[1]); - } else if ($styleWidth) { - $this->style->setHeight($imgData[1] * ($styleWidth / $imgData[0])); + $this->style->setWidth($actualWidth); + $this->style->setHeight($actualHeight); + } elseif ($styleWidth) { + $this->style->setHeight($actualHeight * ($styleWidth / $actualWidth)); } else { - $this->style->setWidth($imgData[0] * ($styleHeight / $imgData[1])); + $this->style->setWidth($actualWidth * ($styleHeight / $actualHeight)); } } $this->setImageFunctions(); diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index 6ec6743a..eae9fc5f 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -129,7 +129,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase public function testPNG() { $src = __DIR__ . "/../_files/images/firefox.png"; - $oImage = new Image($src); + $oImage = new Image($src, array('width' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); @@ -146,7 +146,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase public function testGIF() { $src = __DIR__ . "/../_files/images/mario.gif"; - $oImage = new Image($src); + $oImage = new Image($src, array('height' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); From 19a69e2c39d91f56eefaf2e6cb0ec1888c972b04 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 12 Apr 2014 10:12:24 +0700 Subject: [PATCH 005/326] Basic HTML writer --- CHANGELOG.md | 3 +- samples/Sample_01_SimpleText.php | 12 +- samples/Sample_02_TabStops.php | 12 +- samples/Sample_03_Sections.php | 12 +- samples/Sample_04_Textrun.php | 12 +- samples/Sample_05_Multicolumn.php | 12 +- samples/Sample_06_Footnote.php | 12 +- samples/Sample_08_ParagraphPagination.php | 12 +- samples/Sample_09_Tables.php | 12 +- samples/Sample_10_EastAsianFontStyle.php | 12 +- samples/Sample_11_ReadWord2007.php | 13 +- samples/Sample_12_HeaderFooter.php | 13 +- samples/Sample_13_Images.php | 13 +- samples/Sample_14_ListItem.php | 13 +- samples/Sample_15_Link.php | 14 +- samples/Sample_16_Object.php | 14 +- samples/Sample_17_TitleTOC.php | 13 +- samples/Sample_18_Watermark.php | 14 +- samples/Sample_19_TextBreak.php | 14 +- samples/Sample_20_BGColor.php | 12 +- samples/Sample_21_TableRowRules.php | 12 +- samples/Sample_22_CheckBox.php | 12 +- samples/Sample_Footer.php | 23 - samples/Sample_Header.php | 50 ++ samples/index.php | 6 +- src/PhpWord/Element/Title.php | 10 + src/PhpWord/IOFactory.php | 4 +- src/PhpWord/Writer/HTML.php | 589 ++++++++++++++++++++++ tests/PhpWord/Tests/Writer/HTMLTest.php | 105 ++++ 29 files changed, 826 insertions(+), 229 deletions(-) create mode 100644 src/PhpWord/Writer/HTML.php create mode 100644 tests/PhpWord/Tests/Writer/HTMLTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 03400d46..f9bcdd19 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.10.0 - Not yet released -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML writer is initiated. ### Features @@ -31,6 +31,7 @@ This release marked heavy refactorings on internal code structure with the creat - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin +- HTML Writer: Basic HTML writer initiated - @ivanlanin ### Bugfixes diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 02b78bd7..659686d3 100755 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -45,13 +45,7 @@ $section->addTextBreak(); $section->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index dbed59a3..d6e4cdbc 100755 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -33,13 +33,7 @@ $section->addText("Left Aligned\tRight Aligned", null, 'rightTab'); $section->addText("\tCenter Aligned", null, 'centerTab'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index 4953b6a6..bfbc84af 100755 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -26,13 +26,7 @@ $section->addHeader()->addText('Header'); $section->addFooter()->addText('Footer'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 354eadfd..f415ca17 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -34,13 +34,7 @@ $textrun->addObject('resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 478a8dd0..a3083824 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -36,13 +36,7 @@ $section = $phpWord->addSection(array('breakType' => 'continuous')); $section->addText('Normal paragraph again.'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 75120088..1bec44e4 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -38,13 +38,7 @@ $footnote = $section->addFootnote(); $footnote->addText('The reference for this is wrapped in its own line'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index bf1400a0..57fbab09 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -46,13 +46,7 @@ $section->addText('Paragraph with pageBreakBefore = true (default: false). ' . null, array('pageBreakBefore' => true)); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 5af73fb6..fd930b2b 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -85,13 +85,7 @@ $table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); $table->addCell(null, $cellRowContinue); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index 39f449c3..44bca8a6 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -10,13 +10,7 @@ $header = array('size' => 16, 'bold' => true); $section->addText('中文楷体样式测试',array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index e5112e2e..09d9cab0 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -7,13 +7,8 @@ $source = "resources/{$name}.docx"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source); -// (Re)write contents -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 15309041..8e053286 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -59,15 +59,8 @@ $sec2Header->addText("All pages in Section 2 will Have this!"); $section2->addTextBreak(); $section2->addText('Some text...'); - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 4ef325b8..c8199cce 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -18,16 +18,9 @@ $section->addTextBreak(2); $source = 'http://php.net/images/logos/php-med-trans-light.gif'; $section->addText("Remote image from: {$source}"); $section->addImage($source); -// End code // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 45d9c1a7..cd22df8e 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -54,15 +54,8 @@ $section->addListItem('List Item 6', 1, 'myOwnStyle', $predefinedMultilevel, 'P- $section->addListItem('List Item 7', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); $section->addTextBreak(2); - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index c4435ac0..1bd61e79 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -16,16 +16,8 @@ $phpWord->addLinkStyle('myOwnLinkStyle', array('bold'=>true, 'color'=>'808000')) $section->addLink('http://www.bing.com', null, 'myOwnLinkStyle'); $section->addLink('http://www.yahoo.com', null, 'myOwnLinkStyle'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index cb8de6db..af23a00f 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -11,16 +11,8 @@ $section->addText('You can open this OLE object by double clicking on the icon:' $section->addTextBreak(2); $section->addObject('resources/_sheet.xls'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 15de531b..b18b1bc9 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -67,16 +67,9 @@ $section->addTitle('Subtitle 3.1.2', 3); $section->addText('Text'); echo date('H:i:s'), " Note: Please refresh TOC manually.", EOL; -// End code // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index d0ea786a..313cfbed 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -12,16 +12,8 @@ $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); $section->addText('The header reference to the current section includes a watermark image.'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index d7e11ea4..a209ce39 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -25,16 +25,8 @@ $section->addText('Text break with inline paragraph style:'); $section->addTextBreak(1, null, $paragraphStyle); $section->addText('Done.'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index fec40859..892cd8b2 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -11,13 +11,7 @@ $section->addText("This one uses bgColor and is using hex value (0xfbbb10)", arr $section->addText("Compatible with font colors", array("color"=>"0000ff", "bgColor" => "fbbb10")); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 10ad156d..b600ec00 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -28,13 +28,7 @@ $section->addText("In this example, image is 250px height. Rows are calculated i $section->addText("So: $"."table2->addRow(3750, array('exactHeight'=>true));"); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 89827388..e7aae5ba 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -15,13 +15,7 @@ $cell = $table->addCell(); $cell->addCheckBox('chkBox2', 'Checkbox 2'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_Footer.php b/samples/Sample_Footer.php index 4d5777c2..f7e2305f 100644 --- a/samples/Sample_Footer.php +++ b/samples/Sample_Footer.php @@ -2,33 +2,10 @@ /** * Footer file */ -// Do not show execution time for index -if (!IS_INDEX) { - echo date('H:i:s'), " Done writing file(s)", EOL; - echo date('H:i:s'), " Peak memory usage: ", (memory_get_peak_usage(true) / 1024 / 1024), " MB", EOL; -} -// Show message when executed with CLI, show links when using browsers -if (CLI) { - echo 'The results are stored in the "results" subdirectory.', EOL; -} else { - if (!IS_INDEX) { - $types = array('docx', 'odt', 'rtf'); - echo '

 

'; - echo '
'; - } ?> -{$pageHeading}"; + +// Set writers +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html'); + // Populate samples $files = ''; if ($handle = opendir('.')) { @@ -32,6 +36,52 @@ if ($handle = opendir('.')) { } closedir($handle); } + +/** + * Get results + * + * @param array $writers + * @param string $filename + * @return string + */ +function write($phpWord, $filename, $writers) +{ + $result = ''; + + // Write + foreach ($writers as $writer => $extension) { + $result .= date('H:i:s') . " Write to {$writer} format" . EOL; + $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); + $xmlWriter->save("{$filename}.{$extension}"); + rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + } + + // Do not show execution time for index + if (!IS_INDEX) { + $result .= date('H:i:s') . " Done writing file(s)" . EOL; + $result .= date('H:i:s') . " Peak memory usage: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MB" . EOL; + } + + // Return + if (CLI) { + $result .= 'The results are stored in the "results" subdirectory.' . EOL; + } else { + if (!IS_INDEX) { + $types = array_values($writers); + $result .= '

 

'; + $result .= '

Results: '; + foreach ($types as $type) { + $resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type; + if (file_exists($resultFile)) { + $result .= "{$type} "; + } + } + $result .= '

'; + } + } + + return $result; +} ?> <?php echo $pageTitle; ?> diff --git a/samples/index.php b/samples/index.php index 451cf381..8c742729 100644 --- a/samples/index.php +++ b/samples/index.php @@ -24,5 +24,7 @@ foreach ($requirements as $key => $value) { echo "
  • {$value[0]} ... {$status}
  • "; } echo ""; -} // if (!CLI) -include_once 'Sample_Footer.php'; +} +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 5ed1bfbc..93b48d62 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -119,6 +119,16 @@ class Title extends AbstractElement return $this->text; } + /** + * Get depth + * + * @return integer + */ + public function getDepth() + { + return $this->depth; + } + /** * Get Title style * diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index ade4398e..c15ec821 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -28,7 +28,7 @@ abstract class IOFactory */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if ($name !== 'WriterInterface' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') { + if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) { throw new Exception("\"{$name}\" is not a valid writer."); } @@ -45,7 +45,7 @@ abstract class IOFactory */ public static function createReader($name = 'Word2007') { - if ($name !== 'ReaderInterface' && $name !== 'Word2007') { + if (!in_array($name, array('ReaderInterface', 'Word2007'))) { throw new Exception("\"{$name}\" is not a valid reader."); } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php new file mode 100644 index 00000000..797dd9dc --- /dev/null +++ b/src/PhpWord/Writer/HTML.php @@ -0,0 +1,589 @@ +setPhpWord($phpWord); + } + + /** + * Save PhpWord to file + * + * @param string $filename + * @throws Exception + */ + public function save($filename = null) + { + if (!is_null($this->getPhpWord())) { + $hFile = fopen($filename, 'w') or die("can't open file"); + fwrite($hFile, $this->writeDocument()); + fclose($hFile); + } else { + throw new Exception("No PHPWord assigned."); + } + } + + /** + * Get phpWord data + * + * @return string + */ + private function writeDocument() + { + $html = ''; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= $this->writeHTMLHead(); + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= $this->writeHTMLBody(); + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + + return $html; + } + + /** + * Generate HTML header + * + * @return string + */ + public function writeHTMLHead() + { + $properties = $this->getPhpWord()->getDocumentProperties(); + $propertiesMapping = array( + 'creator' => 'author', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '' + ); + $title = $properties->getTitle(); + $title = ($title != '') ? $title : 'PHPWord'; + + $html = ''; + $html .= '' . PHP_EOL; + $html .= '' . htmlspecialchars($title) . '' . PHP_EOL; + foreach ($propertiesMapping as $key => $value) { + $value = ($value == '') ? $key : $value; + $method = "get" . $key; + if ($properties->$method() != '') { + $html .= '' . PHP_EOL; + } + } + $html .= $this->writeStyles(); + + return $html; + } + + /** + * Get content + * + * @return string + */ + public function writeHTMLBody() + { + $phpWord = $this->getPhpWord(); + $html = ''; + + $sections = $phpWord->getSections(); + $countSections = count($sections); + $pSection = 0; + + if ($countSections > 0) { + foreach ($sections as $section) { + $pSection++; + $cellContents = $section->getElements(); + foreach ($cellContents as $element) { + if ($element instanceof Text) { + $html .= $this->writeText($element); + } elseif ($element instanceof TextRun) { + $html .= $this->writeTextRun($element); + } elseif ($element instanceof Link) { + $html .= $this->writeLink($element); + } elseif ($element instanceof Title) { + $html .= $this->writeTitle($element); + } elseif ($element instanceof PreserveText) { + $html .= $this->writePreserveText($element); + } elseif ($element instanceof TextBreak) { + $html .= $this->writeTextBreak($element); + } elseif ($element instanceof PageBreak) { + $html .= $this->writePageBreak($element); + } elseif ($element instanceof Table) { + $html .= $this->writeTable($element); + } elseif ($element instanceof ListItem) { + $html .= $this->writeListItem($element); + } elseif ($element instanceof Image) { + $html .= $this->writeImage($element); + } elseif ($element instanceof Object) { + $html .= $this->writeObject($element); + } elseif ($element instanceof Footnote) { + $html .= $this->writeFootnote($element, true); + } elseif ($element instanceof Endnote) { + $html .= $this->writeEndnote($element, true); + } + } + } + } + + return $html; + } + + /** + * Get text + * + * @param Text $text + * @param boolean $withoutP + * @return string + */ + private function writeText($text, $withoutP = false) + { + $html = ''; + $paragraphStyle = $text->getParagraphStyle(); + $spIsObject = ($paragraphStyle instanceof Paragraph); + $fontStyle = $text->getFontStyle(); + $sfIsObject = ($fontStyle instanceof Font); + + if ($paragraphStyle && !$withoutP) { + $html .= 'writeParagraphStyle($paragraphStyle) . '"'; + } + $html .= '>'; + } + if ($fontStyle) { + $html .= 'writeFontStyle($fontStyle) . '"'; + } + $html .= '>'; + } + $html .= htmlspecialchars($text->getText()); + if ($fontStyle) { + $html .= ''; + } + if ($paragraphStyle && !$withoutP) { + $html .= '

    ' . PHP_EOL; + } + + return $html; + } + + /** + * Get text run content + * + * @param TextRun $textrun + * @return string + */ + private function writeTextRun($textrun) + { + $html = ''; + $elements = $textrun->getElements(); + if (count($elements) > 0) { + $paragraphStyle = $textrun->getParagraphStyle(); + $spIsObject = ($paragraphStyle instanceof Paragraph); + $html .= 'writeParagraphStyle($paragraphStyle) . '"'; + } + } + $html .= '>'; + foreach ($elements as $element) { + if ($element instanceof Text) { + $html .= $this->writeText($element, true); + } elseif ($element instanceof Link) { + $html .= $this->writeLink($element, true); + } elseif ($element instanceof TextBreak) { + $html .= $this->writeTextBreak($element, true); + } elseif ($element instanceof Image) { + $html .= $this->writeImage($element, true); + } elseif ($element instanceof Footnote) { + $html .= $this->writeFootnote($element, true); + } elseif ($element instanceof Endnote) { + $html .= $this->writeEndnote($element, true); + } + } + $html .= '

    ' . PHP_EOL; + } + + return $html; + } + + /** + * Write link + * + * @param Link $element + * @return string + */ + private function writeLink($element, $withoutP = false) + { + $url = $element->getLinkSrc(); + $text = $element->getLinkName(); + $html = ''; + if (!$withoutP) { + $html .= "

    " . PHP_EOL; + } + $html .= "{$text}" . PHP_EOL; + if (!$withoutP) { + $html .= "

    " . PHP_EOL; + } + + return $html; + } + + /** + * Write heading + * + * @param Title $element + * @return string + */ + private function writeTitle($element) + { + $tag = 'h' . $element->getDepth(); + $text = htmlspecialchars($element->getText()); + $html = "<{$tag}>{$text}" . PHP_EOL; + + return $html; + } + + /** + * Write preserve text + * + * @param PreserveText $element + * @return string + */ + private function writePreserveText($element, $withoutP = false) + { + return $this->writeUnsupportedElement($element, $withoutP); + } + + /** + * Get text break + * + * @param TextBreak $element + * @param boolean $withoutP + * @return string + */ + private function writeTextBreak($element, $withoutP = false) + { + if ($withoutP) { + $html = '
    ' . PHP_EOL; + } else { + $html = '

     

    ' . PHP_EOL; + } + + return $html; + } + + /** + * Write page break + * + * @param PageBreak $element + * @return string + */ + private function writePageBreak($element) + { + return $this->writeUnsupportedElement($element, false); + } + + /** + * Write list item + * + * @param ListItem $element + * @return string + */ + private function writeListItem($element) + { + return $this->writeUnsupportedElement($element, false); + } + + /** + * Write table + * + * @param Title $element + * @return string + */ + private function writeTable($element) + { + $html = ''; + $rows = $element->getRows(); + $cRows = count($rows); + if ($cRows > 0) { + $html .= "" . PHP_EOL; + foreach ($rows as $row) { + $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $html .= "" . PHP_EOL; + foreach ($row->getCells() as $cell) { + $cellTag = $tblHeader ? 'th' : 'td'; + $cellContents = $cell->getElements(); + $html .= "<{$cellTag}>" . PHP_EOL; + if (count($cellContents) > 0) { + foreach ($cellContents as $content) { + if ($content instanceof Text) { + $html .= $this->writeText($content); + } elseif ($content instanceof TextRun) { + $html .= $this->writeTextRun($content); + } elseif ($content instanceof Link) { + $html .= $this->writeLink($content); + } elseif ($content instanceof PreserveText) { + $html .= $this->writePreserveText($content); + } elseif ($content instanceof TextBreak) { + $html .= $this->writeTextBreak($content); + } elseif ($content instanceof ListItem) { + $html .= $this->writeListItem($content); + } elseif ($content instanceof Image) { + $html .= $this->writeImage($content); + } elseif ($content instanceof Object) { + $html .= $this->writeObject($content); + } elseif ($element instanceof Footnote) { + $html .= $this->writeFootnote($element, true); + } elseif ($element instanceof Endnote) { + $html .= $this->writeEndnote($element, true); + } + } + } else { + $this->writeTextBreak($content); + } + $html .= "" . PHP_EOL; + } + $html .= "" . PHP_EOL; + } + $html .= "
    " . PHP_EOL; + } + + return $html; + } + + /** + * Write image + * + * @param Image $element + * @return string + */ + private function writeImage($element, $withoutP = false) + { + return $this->writeUnsupportedElement($element, $withoutP); + } + + /** + * Write object + * + * @param Object $element + * @return string + */ + private function writeObject($element, $withoutP = false) + { + return $this->writeUnsupportedElement($element, $withoutP); + } + + /** + * Write footnote + * + * @param Footnote $element + * @return string + */ + private function writeFootnote($element) + { + return $this->writeUnsupportedElement($element, true); + } + + /** + * Write endnote + * + * @param Endnote $element + * @return string + */ + private function writeEndnote($element) + { + return $this->writeUnsupportedElement($element, true); + } + + /** + * Write unsupported element + * + * @param mixed $element + * @param boolean $withoutP + * @return string + */ + private function writeUnsupportedElement($element, $withoutP = false) + { + $elementClass = get_class($element); + $elementMark = str_replace('PhpOffice\\PhpWord\\Element\\', '', $elementClass); + $elementMark = htmlentities("<{$elementMark}>"); + if ($withoutP) { + $html = "{$elementMark}" . PHP_EOL; + } else { + $html = "

    {$elementMark}

    " . PHP_EOL; + } + + return $html; + } + + /** + * Get styles + * + * @return string + */ + private function writeStyles() + { + $css = '' . PHP_EOL; + + return $css; + } + + /** + * Get font style + * + * @param Font $style + * @param boolean $curlyBracket + * @return string + */ + private function writeFontStyle($style, $curlyBracket = false) + { + $css = array(); + if (PHPWord::DEFAULT_FONT_NAME != $style->getName()) { + $css['font-family'] = "'" . $style->getName() . "'"; + } + if (PHPWord::DEFAULT_FONT_SIZE != $style->getSize()) { + $css['font-size'] = $style->getSize() . 'pt'; + } + if (PHPWord::DEFAULT_FONT_COLOR != $style->getColor()) { + $css['color'] = '#' . $style->getColor(); + } + $css['background'] = $style->getFgColor(); + if ($style->getBold()) { + $css['font-weight'] = 'bold'; + } + if ($style->getItalic()) { + $css['font-style'] = 'italic'; + } + if ($style->getSuperScript()) { + $css['vertical-align'] = 'super'; + } elseif ($style->getSubScript()) { + $css['vertical-align'] = 'sub'; + } + $css['text-decoration'] = ''; + if ($style->getUnderline() != Font::UNDERLINE_NONE) { + $css['text-decoration'] .= 'underline '; + } + if ($style->getStrikethrough()) { + $css['text-decoration'] .= 'line-through '; + } + + return $this->assembleCss($css, $curlyBracket); + } + + /** + * Get paragraph style + * + * @param Paragraph $style + * @param boolean $curlyBracket + * @return string + */ + private function writeParagraphStyle($style, $curlyBracket = false) + { + $css = array(); + if ($style->getAlign()) { + $css['text-align'] = $style->getAlign(); + } + + return $this->assembleCss($css, $curlyBracket); + } + + /** + * Takes array where of CSS properties / values and converts to CSS string + * + * @param array $css + * @param boolean $curlyBracket + * @return string + */ + private function assembleCss($css, $curlyBracket = false) + { + $pairs = array(); + foreach ($css as $key => $value) { + if ($value != '') { + $pairs[] = $key . ': ' . $value; + } + } + $string = implode('; ', $pairs); + if ($curlyBracket) { + $string = '{ ' . $string . ' }'; + } + + return $string; + } +} diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php new file mode 100644 index 00000000..40ea88b0 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -0,0 +1,105 @@ +assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); + } + + /** + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage No PhpWord assigned. + */ + public function testConstructWithNull() + { + $object = new HTML(); + $object->getPhpWord(); + } + + /** + * Save + */ + public function testSave() + { + $imageSrc = __DIR__ . "/../_files/images/PhpWord.png"; + $objectSrc = __DIR__ . "/../_files/documents/sheet.xls"; + $file = __DIR__ . "/../_files/temp.html"; + + $phpWord = new PhpWord(); + + $docProps = $phpWord->getDocumentProperties(); + $docProps->setTitle('HTML Test'); + + $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); + $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $section = $phpWord->addSection(); + $section->addText('Test 1', 'Font', 'Paragraph'); + $section->addTextBreak(); + $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true)); + $section->addLink('http://test.com'); + $section->addTitle('Test', 1); + $section->addPageBreak(); + $section->addListItem('Test'); + $section->addImage($imageSrc); + $section->addObject($objectSrc); + $section->addFootnote(); + $section->addEndnote(); + + $section = $phpWord->addSection(); + + $textrun = $section->addTextRun(array('align' => 'center')); + $textrun->addText('Test 3'); + $textrun->addTextBreak(); + + $textrun = $section->addTextRun('Paragraph'); + $textrun->addLink('http://test.com'); + $textrun->addImage($imageSrc); + $textrun->addFootnote(); + $textrun->addEndnote(); + + $section = $phpWord->addSection(); + + $table = $section->addTable(); + $cell = $table->addRow()->addCell(); + $cell->addText('Test 1', array('superscript' => true, 'underline' => 'dash', 'strikethrough' => true)); + $cell->addTextRun(); + $cell->addLink('http://test.com'); + $cell->addTextBreak(); + $cell->addListItem('Test'); + $cell->addImage($imageSrc); + $cell->addObject($objectSrc); + $cell->addFootnote(); + $cell->addEndnote(); + + $writer = new HTML($phpWord); + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } +} From 5a01927b1622b3e3a1cb34cb76fb77dc04a9dd38 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 22:25:42 +0700 Subject: [PATCH 006/326] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806c9c1c..d6b7bfb5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ This release marked heavy refactorings on internal code structure with the creat - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin - Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 -- HTML Writer: Basic HTML writer initiated - @ivanlanin +- HTML Writer: Basic HTML writer initiated - @ivanlanin GH-203 GH-67 GH-147 ### Bugfixes From 580a61a832929312cb7bc7fe6aba72fd00ab147f Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 23:17:39 +0700 Subject: [PATCH 007/326] Basic PDF Writer #68 --- CHANGELOG.md | 3 +- samples/Sample_Header.php | 26 ++- src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Settings.php | 98 ++++++++- src/PhpWord/Writer/HTML.php | 36 ++-- src/PhpWord/Writer/PDF.php | 66 ++++++ src/PhpWord/Writer/PDF/Core.php | 194 ++++++++++++++++++ src/PhpWord/Writer/PDF/DomPDF.php | 72 +++++++ .../PhpWord/Tests/Style/AbstractStyleTest.php | 4 + 9 files changed, 473 insertions(+), 28 deletions(-) create mode 100644 src/PhpWord/Writer/PDF.php create mode 100644 src/PhpWord/Writer/PDF/Core.php create mode 100644 src/PhpWord/Writer/PDF/DomPDF.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b7bfb5..d8268a73 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.10.0 - Not yet released -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML support is enabled. +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled. ### Features @@ -33,6 +33,7 @@ This release marked heavy refactorings on internal code structure with the creat - ODT Writer: Basic table writing support - @ivanlanin - Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 - HTML Writer: Basic HTML writer initiated - @ivanlanin GH-203 GH-67 GH-147 +- PDF Writer: Basic PDF writer initiated using DomPDF - @ivanlanin GH-68 ### Bugfixes diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index e3057db7..04fd8a40 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -11,6 +11,16 @@ define('IS_INDEX', SCRIPT_FILENAME == 'index'); require_once '../src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); +// Set writers +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'); + +// Set PDF renderer +$rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_DOMPDF; +$rendererLibraryPath = ""; // Put dompdf library path +if (!\PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName, $rendererLibraryPath)) { + $writers['PDF'] = null; +} + // Return to the caller script when runs by CLI if (CLI) { return; @@ -22,9 +32,6 @@ $pageTitle = IS_INDEX ? 'Welcome to ' : "{$pageHeading} - "; $pageTitle .= 'PHPWord'; $pageHeading = IS_INDEX ? '' : "

    {$pageHeading}

    "; -// Set writers -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html'); - // Populate samples $files = ''; if ($handle = opendir('.')) { @@ -51,10 +58,15 @@ function write($phpWord, $filename, $writers) // Write foreach ($writers as $writer => $extension) { - $result .= date('H:i:s') . " Write to {$writer} format" . EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$filename}.{$extension}"); - rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + $result .= date('H:i:s') . " Write to {$writer} format"; + if (!is_null($extension)) { + $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); + $xmlWriter->save("{$filename}.{$extension}"); + rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + } else { + $result .= ' ... NOT DONE!'; + } + $result .= EOL; } // Do not show execution time for index diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index c15ec821..9f7c8162 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -28,7 +28,7 @@ abstract class IOFactory */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) { + if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML', 'PDF'))) { throw new Exception("\"{$name}\" is not a valid writer."); } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 0af6cf72..4558736b 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -14,10 +14,13 @@ namespace PhpOffice\PhpWord; */ class Settings { - /** Available Zip library classes */ + /** Available Zip library classes */ const PCLZIP = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; const ZIPARCHIVE = 'ZipArchive'; + /** Optional PDF Rendering libraries */ + const PDF_RENDERER_DOMPDF = 'DomPDF'; + /** * Compatibility option for XMLWriter * @@ -27,13 +30,32 @@ class Settings /** * Name of the class used for Zip file management - * e.g. - * ZipArchive * * @var string */ private static $zipClass = self::ZIPARCHIVE; + /** + * Name of the classes used for PDF renderer + * + * @var array + */ + private static $pdfRenderers = array(self::PDF_RENDERER_DOMPDF); + + /** + * Name of the external Library used for rendering PDF files + * + * @var string + */ + private static $pdfRendererName = null; + + /** + * Directory Path to the external Library used for rendering PDF files + * + * @var string + */ + private static $pdfRendererPath = null; + /** * Set the compatibility option used by the XMLWriter * @@ -74,7 +96,7 @@ class Settings return true; } return false; - } // function setZipClass() + } /** * Return the name of the Zip handler Class that PHPWord is configured to use (PCLZip or ZipArchive) @@ -87,5 +109,71 @@ class Settings public static function getZipClass() { return self::$zipClass; - } // function getZipClass() + } + + /** + * Set details of the external library for rendering PDF files + * + * @param string $libraryName + * @param string $libraryBaseDir + * @return boolean Success or failure + */ + public static function setPdfRenderer($libraryName, $libraryBaseDir) + { + if (!self::setPdfRendererName($libraryName)) { + return false; + } + + return self::setPdfRendererPath($libraryBaseDir); + } + + /** + * Return the PDF Rendering Library + */ + public static function getPdfRendererName() + { + return self::$pdfRendererName; + } + + /** + * Identify the external library to use for rendering PDF files + * + * @param string $libraryName + * @return boolean Success or failure + */ + public static function setPdfRendererName($libraryName) + { + if (!in_array($libraryName, self::$pdfRenderers)) { + return false; + } + + self::$pdfRendererName = $libraryName; + + return true; + } + + + /** + * Return the directory path to the PDF Rendering Library + */ + public static function getPdfRendererPath() + { + return self::$pdfRendererPath; + } + + /** + * Location of external library to use for rendering PDF files + * + * @param string $libraryBaseDir Directory path to the library's base folder + * @return boolean Success or failure + */ + public static function setPdfRendererPath($libraryBaseDir) + { + if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) { + return false; + } + self::$pdfRendererPath = $libraryBaseDir; + + return true; + } } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 797dd9dc..f0879332 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -16,6 +16,7 @@ use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Element\ListItem; use PhpOffice\PhpWord\Element\Object; use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\PreserveText; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextBreak; @@ -65,7 +66,7 @@ class HTML extends AbstractWriter implements WriterInterface * * @return string */ - private function writeDocument() + public function writeDocument() { $html = ''; $html .= '' . PHP_EOL; @@ -87,7 +88,7 @@ class HTML extends AbstractWriter implements WriterInterface * * @return string */ - public function writeHTMLHead() + private function writeHTMLHead() { $properties = $this->getPhpWord()->getDocumentProperties(); $propertiesMapping = array( @@ -124,7 +125,7 @@ class HTML extends AbstractWriter implements WriterInterface * * @return string */ - public function writeHTMLBody() + private function writeHTMLBody() { $phpWord = $this->getPhpWord(); $html = ''; @@ -136,8 +137,8 @@ class HTML extends AbstractWriter implements WriterInterface if ($countSections > 0) { foreach ($sections as $section) { $pSection++; - $cellContents = $section->getElements(); - foreach ($cellContents as $element) { + $contents = $section->getElements(); + foreach ($contents as $element) { if ($element instanceof Text) { $html .= $this->writeText($element); } elseif ($element instanceof TextRun) { @@ -161,9 +162,9 @@ class HTML extends AbstractWriter implements WriterInterface } elseif ($element instanceof Object) { $html .= $this->writeObject($element); } elseif ($element instanceof Footnote) { - $html .= $this->writeFootnote($element, true); + $html .= $this->writeFootnote($element); } elseif ($element instanceof Endnote) { - $html .= $this->writeEndnote($element, true); + $html .= $this->writeEndnote($element); } } } @@ -248,9 +249,9 @@ class HTML extends AbstractWriter implements WriterInterface } elseif ($element instanceof Image) { $html .= $this->writeImage($element, true); } elseif ($element instanceof Footnote) { - $html .= $this->writeFootnote($element, true); + $html .= $this->writeFootnote($element); } elseif ($element instanceof Endnote) { - $html .= $this->writeEndnote($element, true); + $html .= $this->writeEndnote($element); } } $html .= '

    ' . PHP_EOL; @@ -263,6 +264,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write link * * @param Link $element + * @param boolean $withoutP * @return string */ private function writeLink($element, $withoutP = false) @@ -300,6 +302,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write preserve text * * @param PreserveText $element + * @param boolean $withoutP * @return string */ private function writePreserveText($element, $withoutP = false) @@ -350,7 +353,7 @@ class HTML extends AbstractWriter implements WriterInterface /** * Write table * - * @param Title $element + * @param Table $element * @return string */ private function writeTable($element) @@ -361,7 +364,7 @@ class HTML extends AbstractWriter implements WriterInterface if ($cRows > 0) { $html .= "" . PHP_EOL; foreach ($rows as $row) { - $height = $row->getHeight(); + // $height = $row->getHeight(); $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); $html .= "" . PHP_EOL; @@ -388,13 +391,13 @@ class HTML extends AbstractWriter implements WriterInterface } elseif ($content instanceof Object) { $html .= $this->writeObject($content); } elseif ($element instanceof Footnote) { - $html .= $this->writeFootnote($element, true); + $html .= $this->writeFootnote($element); } elseif ($element instanceof Endnote) { - $html .= $this->writeEndnote($element, true); + $html .= $this->writeEndnote($element); } } } else { - $this->writeTextBreak($content); + $html .= $this->writeTextBreak(new TextBreak()); } $html .= "" . PHP_EOL; } @@ -410,6 +413,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write image * * @param Image $element + * @param boolean $withoutP * @return string */ private function writeImage($element, $withoutP = false) @@ -421,6 +425,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write object * * @param Object $element + * @param boolean $withoutP * @return string */ private function writeObject($element, $withoutP = false) @@ -478,11 +483,14 @@ class HTML extends AbstractWriter implements WriterInterface */ private function writeStyles() { + $bodyCss = array(); $css = '' . PHP_EOL; - - return $css; - } - - /** - * Write footnote/endnote contents as textruns - */ - private function writeNotes() - { - $phpWord = $this->getPhpWord(); - $content = PHP_EOL; - - if (!empty($this->notes)) { - $content .= "
    " . PHP_EOL; - foreach ($this->notes as $noteId => $noteMark) { - list($noteType, $noteTypeId) = explode('-', $noteMark); - $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); - $collection = $phpWord->$method()->getItems(); - - if (array_key_exists($noteTypeId, $collection)) { - $element = $collection[$noteTypeId]; - $noteAnchor = ""; - $noteAnchor .= "{$noteId}"; - - $writer = new TextRunWriter($this, $element); - $writer->setOpeningText($noteAnchor); - $content .= $writer->write(); - } - } - } - - return $content; - } - /** * Get is PDF * diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index dafc1c38..698b7e86 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -88,7 +88,7 @@ class Image extends Text } else { $actualSource = $source; } - if (is_null($actualSource)) { + if ($actualSource === null) { return null; } @@ -100,12 +100,13 @@ class Image extends Text $imageBinary = ob_get_contents(); ob_end_clean(); } else { - if ($fileHandle = fopen($actualSource, 'rb', false)) { + $fileHandle = fopen($actualSource, 'rb', false); + if ($fileHandle !== false) { $imageBinary = fread($fileHandle, filesize($actualSource)); fclose($fileHandle); } } - if (!is_null($imageBinary)) { + if ($imageBinary !== null) { $base64 = chunk_split(base64_encode($imageBinary)); $imageData = 'data:' . $imageType . ';base64,' . $base64; } diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php new file mode 100644 index 00000000..319aa20f --- /dev/null +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -0,0 +1,68 @@ +parentWriter = $writer; + } + + /** + * Get parent writer + * + * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function getParentWriter() + { + if ($this->parentWriter !== null) { + return $this->parentWriter; + } else { + throw new Exception('No parent WriterInterface assigned.'); + } + } +} diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php new file mode 100644 index 00000000..4fd61a83 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -0,0 +1,89 @@ +getParentWriter()->getPhpWord(); + + $content = ''; + + $content .= '' . PHP_EOL; + $sections = $phpWord->getSections(); + foreach ($sections as $section) { + $writer = new Container($this->getParentWriter(), $section); + $content .= $writer->write(); + } + + $content .= $this->writeNotes(); + $content .= '' . PHP_EOL; + + return $content; + } + + /** + * Write footnote/endnote contents as textruns + * + * @return string + */ + private function writeNotes() + { + /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ + $parentWriter = $this->getParentWriter(); + $phpWord = $parentWriter->getPhpWord(); + $notes = $parentWriter->getNotes(); + + $content = ''; + + if (!empty($notes)) { + $content .= "
    " . PHP_EOL; + foreach ($notes as $noteId => $noteMark) { + list($noteType, $noteTypeId) = explode('-', $noteMark); + $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); + $collection = $phpWord->$method()->getItems(); + + if (array_key_exists($noteTypeId, $collection)) { + $element = $collection[$noteTypeId]; + $noteAnchor = ""; + $noteAnchor .= "{$noteId}"; + + $writer = new TextRunWriter($this->getParentWriter(), $element); + $writer->setOpeningText($noteAnchor); + $content .= $writer->write(); + } + } + } + + return $content; + } +} diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php new file mode 100644 index 00000000..389d568b --- /dev/null +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -0,0 +1,129 @@ +getParentWriter()->getPhpWord()->getDocumentProperties(); + $propertiesMapping = array( + 'creator' => 'author', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '' + ); + $title = $docProps->getTitle(); + $title = ($title != '') ? $title : 'PHPWord'; + + $content = ''; + + $content .= '' . PHP_EOL; + $content .= '' . PHP_EOL; + $content .= '' . htmlspecialchars($title) . '' . PHP_EOL; + foreach ($propertiesMapping as $key => $value) { + $value = ($value == '') ? $key : $value; + $method = "get" . $key; + if ($docProps->$method() != '') { + $content .= '' . PHP_EOL; + } + } + $content .= $this->writeStyles(); + $content .= '' . PHP_EOL; + + return $content; + } + /** + * Get styles + * + * @return string + */ + private function writeStyles() + { + $css = '' . PHP_EOL; + + return $css; + } +} diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index f7266d1a..83b02251 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -84,6 +84,7 @@ abstract class AbstractRenderer extends HTML parent::__construct($phpWord); $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; if (file_exists($includeFile)) { + /** @noinspection PhpIncludeInspection Dynamic includes */ require_once $includeFile; } else { throw new Exception('Unable to load PDF Rendering library'); diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index aaf412de..ef94b264 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -35,7 +35,8 @@ class RTF extends AbstractWriter implements WriterInterface private $lastParagraphStyle; /** - * Create new RTF writer + * Create new instance + * * @param \PhpOffice\PhpWord\PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) @@ -52,7 +53,6 @@ class RTF extends AbstractWriter implements WriterInterface $this->writerParts[strtolower($partName)] = $part; } } - } /** diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 3a73a226..b10e5654 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -17,52 +17,13 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Writer\AbstractWriter; +use PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart as HTMLAbstractPart; /** * Abstract RTF part writer * * @since 0.11.0 */ -abstract class AbstractPart +abstract class AbstractPart extends HTMLAbstractPart { - /** - * Parent writer - * - * @var \PhpOffice\PhpWord\Writer\AbstractWriter - */ - private $parentWriter; - - /** - * Write part - * - * @return string - */ - abstract public function write(); - - /** - * Set parent writer - * - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - */ - public function setParentWriter(AbstractWriter $writer = null) - { - $this->parentWriter = $writer; - } - - /** - * Get parent writer - * - * @return \PhpOffice\PhpWord\Writer\AbstractWriter - * @throws \PhpOffice\PhpWord\Exception\Exception - */ - public function getParentWriter() - { - if ($this->parentWriter !== null) { - return $this->parentWriter; - } else { - throw new Exception('No parent WriterInterface assigned.'); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 7d1c8104..3dad824d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,8 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Container element writer (section, textrun, header, footnote, cell, etc.) @@ -51,36 +53,52 @@ class Container extends AbstractElement $elements = $container->getElements(); $elementClass = ''; foreach ($elements as $element) { - $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); - $writerClass = $this->namespace . '\\' . $elementClass; - - // Check it's a page break. No need to write it, instead, flag containers' pageBreakBefore - // to be assigned to the next element - if ($elementClass == 'PageBreak') { - $this->setPageBreakBefore(true); - continue; - } - if (class_exists($writerClass)) { - // Get container's page break before and reset it - $pageBreakBefore = $this->hasPageBreakBefore(); - $this->setPageBreakBefore(false); - - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ - $writer = new $writerClass($xmlWriter, $element, $withoutP); - $writer->setPageBreakBefore($pageBreakBefore); - $writer->write(); - } + $elementClass = $this->writeElement($xmlWriter, $element, $withoutP); } - // Special case for Cell: They have to contain a w:p element at the end. The $elementClass contains - // the last element name. If it's empty string or Table, the last element is not w:p - if ($containerClass == 'Cell') { - if ($elementClass == '' || $elementClass == 'Table') { - $writerClass = $this->namespace . '\\TextBreak'; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ - $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); - $writer->write(); - } + // Special case for Cell: They have to contain a w:p element at the end. + // The $elementClass contains the last element name. If it's empty string + // or Table, the last element is not w:p + $writeLastTextBreak = ($containerClass == 'Cell') && ($elementClass == '' || $elementClass == 'Table'); + if ($writeLastTextBreak) { + $writerClass = $this->namespace . '\\TextBreak'; + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); + $writer->write(); } } + + /** + * Write individual element + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\AbstractElement $element + * @param bool $withoutP + * @return string + */ + private function writeElement(XMLWriter $xmlWriter, Element $element, $withoutP) + { + $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); + $writerClass = $this->namespace . '\\' . $elementClass; + + // Check it's a page break. No need to write it, instead, flag containers' + // pageBreakBefore to be assigned to the next element + if ($elementClass == 'PageBreak') { + $this->setPageBreakBefore(true); + return $elementClass; + } + + if (class_exists($writerClass)) { + // Get container's page break before and reset it + $pageBreakBefore = $this->hasPageBreakBefore(); + $this->setPageBreakBefore(false); + + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + $writer = new $writerClass($xmlWriter, $element, $withoutP); + $writer->setPageBreakBefore($pageBreakBefore); + $writer->write(); + } + + return $elementClass; + } } From a65c3c3cf1d2628502fbf5f766405466f2b20f68 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 23 May 2014 18:32:56 +0700 Subject: [PATCH 197/326] RTF Writer: Ability to write image --- CHANGELOG.md | 1 + docs/intro.rst | 2 +- docs/src/documentation.md | 2 +- src/PhpWord/Element/AbstractContainer.php | 1 + src/PhpWord/Element/Image.php | 59 +++++++++++++++++++++ src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Writer/HTML/Element/Image.php | 63 ++--------------------- src/PhpWord/Writer/HTML/Part/Head.php | 1 - src/PhpWord/Writer/RTF/Element/Image.php | 57 ++++++++++++++++++++ 9 files changed, 124 insertions(+), 64 deletions(-) create mode 100644 src/PhpWord/Writer/RTF/Element/Image.php diff --git a/CHANGELOG.md b/CHANGELOG.md index daaddb60..68ea9d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r - Word2007 Writer: Enable the missing custom document properties writer - @ivanlanin - Image: Enable "image float left" - @ivanlanin GH-244 - RTF Writer: Ability to write document properties - @ivanlanin +- RTF Writer: Ability to write image - @ivanlanin ### Bugfixes diff --git a/docs/intro.rst b/docs/intro.rst index 55a0764c..a64fb2ad 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -83,7 +83,7 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Table | ✓ | ✓ | | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Image | ✓ | ✓ | | ✓ | | +| | Image | ✓ | ✓ | ✓ | ✓ | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Object | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index dce1f5db..abb8777e 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -89,7 +89,7 @@ Below are the supported features for each file formats. | | Page Break | ✓ | | ✓ | | | | | List | ✓ | | | | | | | Table | ✓ | ✓ | | ✓ | ✓ | -| | Image | ✓ | ✓ | | ✓ | | +| | Image | ✓ | ✓ | ✓ | ✓ | | | | Object | ✓ | | | | | | | Watermark | ✓ | | | | | | | Table of Contents | ✓ | | | | | diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index f469686d..06a94489 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -83,6 +83,7 @@ abstract class AbstractContainer extends AbstractElement $mediaContainer = $this->getMediaContainer(); if (in_array($elementName, array('Link', 'Image', 'Object'))) { if ($elementName == 'Image') { + /** @var \PhpOffice\PhpWord\Element\Image $element Type hint */ $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $element); } else { $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1]); diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 8e30b78c..c38fda2c 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -279,6 +279,65 @@ class Image extends AbstractElement $this->mediaIndex = $value; } + /** + * Get image string data + * + * @param bool $base64 + * @return string|null + */ + public function getImageStringData($base64 = false) + { + $source = $this->source; + $actualSource = null; + $imageBinary = null; + $imageData = null; + + // Get actual source from archive image or other source + // Return null if not found + if ($this->sourceType == self::SOURCE_ARCHIVE) { + $source = substr($source, 6); + list($zipFilename, $imageFilename) = explode('#', $source); + + $zip = new ZipArchive(); + if ($zip->open($zipFilename) !== false) { + if ($zip->locateName($imageFilename)) { + $zip->extractTo(sys_get_temp_dir(), $imageFilename); + $actualSource = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $imageFilename; + } + } + $zip->close(); + } else { + $actualSource = $source; + } + if ($actualSource === null) { + return null; + } + + // Read image binary data and convert to hex + if ($this->sourceType == self::SOURCE_GD) { + $imageResource = call_user_func($this->imageCreateFunc, $actualSource); + ob_start(); + call_user_func($this->imageFunc, $imageResource); + $imageBinary = ob_get_contents(); + ob_end_clean(); + } else { + $fileHandle = fopen($actualSource, 'rb', false); + if ($fileHandle !== false) { + $imageBinary = fread($fileHandle, filesize($actualSource)); + fclose($fileHandle); + } + } + if ($imageBinary !== null) { + if ($base64) { + $imageData = chunk_split(base64_encode($imageBinary)); + } else { + $imageData = chunk_split(bin2hex($imageBinary)); + } + } + + return $imageData; + } + /** * Check memory image, supported type, image functions, and proportional width/height * diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 68b53463..90e8282f 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -430,7 +430,7 @@ class Table extends Border /** * Get cell margin * - * @return integer[] + * @return int[] */ public function getCellMargin() { diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 698b7e86..ab78990b 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\Image as ImageElement; -use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Writer\HTML\Style\Image as ImageStyleWriter; /** @@ -43,10 +42,11 @@ class Image extends Text $content = ''; if (!$parentWriter->isPdf()) { - $imageData = $this->getBase64ImageData($this->element); - if (!is_null($imageData)) { + $imageData = $this->element->getImageStringData(true); + if ($imageData !== null) { $styleWriter = new ImageStyleWriter($this->element->getStyle()); $style = $styleWriter->write(); + $imageData = 'data:' . $this->element->getImageType() . ';base64,' . $imageData; $content .= $this->writeOpening(); $content .= ""; @@ -56,61 +56,4 @@ class Image extends Text return $content; } - - /** - * Get Base64 image data - * - * @param \PhpOffice\PhpWord\Element\Image $element - * @return string|null - */ - private function getBase64ImageData(ImageElement $element) - { - $source = $element->getSource(); - $imageType = $element->getImageType(); - $imageData = null; - $imageBinary = null; - $actualSource = null; - - // Get actual source from archive image or other source - // Return null if not found - if ($element->getSourceType() == ImageElement::SOURCE_ARCHIVE) { - $source = substr($source, 6); - list($zipFilename, $imageFilename) = explode('#', $source); - - $zip = new ZipArchive(); - if ($zip->open($zipFilename) !== false) { - if ($zip->locateName($imageFilename)) { - $zip->extractTo($this->parentWriter->getTempDir(), $imageFilename); - $actualSource = $this->parentWriter->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename; - } - } - $zip->close(); - } else { - $actualSource = $source; - } - if ($actualSource === null) { - return null; - } - - // Read image binary data and convert into Base64 - if ($element->getSourceType() == ImageElement::SOURCE_GD) { - $imageResource = call_user_func($element->getImageCreateFunction(), $actualSource); - ob_start(); - call_user_func($element->getImageFunction(), $imageResource); - $imageBinary = ob_get_contents(); - ob_end_clean(); - } else { - $fileHandle = fopen($actualSource, 'rb', false); - if ($fileHandle !== false) { - $imageBinary = fread($fileHandle, filesize($actualSource)); - fclose($fileHandle); - } - } - if ($imageBinary !== null) { - $base64 = chunk_split(base64_encode($imageBinary)); - $imageData = 'data:' . $imageType . ';base64,' . $base64; - } - - return $imageData; - } } diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 389d568b..edbc8dcf 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -32,7 +32,6 @@ use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; */ class Head extends AbstractPart { - /** * Write part * diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php new file mode 100644 index 00000000..1daae2a0 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -0,0 +1,57 @@ +element instanceof ImageElement) { + return ''; + } + + $this->getStyles(); + $style = $this->element->getStyle(); + + $content = ''; + $content .= $this->writeOpening(); + $content .= '{\*\shppict {\pict'; + $content .= '\pngblip\picscalex100\picscaley100'; + $content .= '\picwgoal' . round(Font::pixelSizeToTwips($style->getWidth())); + $content .= '\pichgoal' . round(Font::pixelSizeToTwips($style->getHeight())); + $content .= PHP_EOL; + $content .= $this->element->getImageStringData(); + $content .= '}}'; + $content .= $this->writeClosing(); + + return $content; + } +} From 991016a48b73d566dce6bc6982c81a2378bbe1fb Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 24 May 2014 00:11:06 +0700 Subject: [PATCH 198/326] Additional writer test --- src/PhpWord/Shared/String.php | 4 ++-- src/PhpWord/Writer/ODText/Part/Content.php | 10 ++++++---- tests/PhpWord/Tests/Writer/HTMLTest.php | 4 ++-- tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php | 8 +++++--- tests/PhpWord/Tests/Writer/ODText/StyleTest.php | 2 +- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 99b8cca3..1e4504cc 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -86,7 +86,7 @@ class String } /** - * Returns unicode array from UTF8 text + * Returns unicode from UTF8 text * * The function is splitted to reduce cyclomatic complexity * @@ -100,7 +100,7 @@ class String } /** - * Returns unicode from UTF8 text + * Returns unicode array from UTF8 text * * @param string $text UTF8 text * @return array diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 900edfdd..f16937a0 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -115,12 +115,14 @@ class Content extends AbstractPart $xmlWriter->startElement('office:automatic-styles'); $this->writeTextStyles($xmlWriter); - foreach ($this->autoStyles as $element => $style) { + foreach ($this->autoStyles as $element => $styles) { $writerClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Style\\' . $element; + foreach ($styles as $style) { - /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ - $styleWriter = new $writerClass($xmlWriter, $style); - $styleWriter->write(); + /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ + $styleWriter = new $writerClass($xmlWriter, $style); + $styleWriter->write(); + } } $xmlWriter->endElement(); // office:automatic-styles diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index 34e9d2bd..0a59b3df 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -92,8 +92,8 @@ class HTMLTest extends \PHPUnit_Framework_TestCase $textrun = $section->addTextRun('Paragraph'); $textrun->addLink('http://test.com'); $textrun->addImage($localImage); - $textrun->addFootnote(); - $textrun->addEndnote(); + $textrun->addFootnote()->addText('Footnote'); + $textrun->addEndnote()->addText('Endnote'); $section = $phpWord->addSection(); diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index 03f0cfeb..42c95bcb 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -51,7 +51,7 @@ class ContentTest extends \PHPUnit_Framework_TestCase $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->addSection(); + $section = $phpWord->addSection(array('colsNum' => 2)); $section->addText($expected); $section->addText('Test font style', 'Font'); $section->addText('Test paragraph style', null, 'Paragraph'); @@ -60,14 +60,14 @@ class ContentTest extends \PHPUnit_Framework_TestCase $section->addTextBreak(); $section->addPageBreak(); $section->addListItem('Test list item'); - $section->addImage($imageSrc); + $section->addImage($imageSrc, array('width' => 50)); $section->addObject($objectSrc); $section->addTOC(); $textrun = $section->addTextRun(); $textrun->addText('Test text run'); - $table = $section->addTable(); + $table = $section->addTable(array('width' => 50)); $cell = $table->addRow()->addCell(); $cell = $table->addRow()->addCell(); $cell->addText('Test'); @@ -82,6 +82,8 @@ class ContentTest extends \PHPUnit_Framework_TestCase $footer = $section->addFooter(); $footer->addPreserveText('{PAGE}'); + $table = $section->addTable('tblStyle')->addRow()->addCell(); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); $element = "/office:document-content/office:body/office:text/text:section/text:p"; diff --git a/tests/PhpWord/Tests/Writer/ODText/StyleTest.php b/tests/PhpWord/Tests/Writer/ODText/StyleTest.php index 387accfc..cd5ea0eb 100644 --- a/tests/PhpWord/Tests/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/StyleTest.php @@ -28,7 +28,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase */ public function testEmptyStyles() { - $styles = array('Font', 'Paragraph'); + $styles = array('Font', 'Paragraph', 'Image', 'Section', 'Table'); foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Style\\' . $style; $xmlWriter = new XMLWriter(); From 248d82d3c300ef5881ede2e29787207c94cb368e Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 24 May 2014 10:53:09 +0700 Subject: [PATCH 199/326] Add two recipes --- docs/recipes.rst | 39 +++++++++++++++++++++++++++++++++++++++ docs/src/documentation.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/docs/recipes.rst b/docs/recipes.rst index 033452b3..d900af8a 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -2,3 +2,42 @@ Recipes ======= + +Create float left image +----------------------- + +Use absolute positioning relative to margin horizontally and to line +vertically. + +.. code-block:: php + + $imageStyle = array( + 'width' => 40, + 'height' => 40 + 'wrappingStyle' => 'square', + 'positioning' => 'absolute', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'line', + ); + $textrun->addImage('resources/_earth.jpg', $imageStyle); + $textrun->addText($lipsumText); + +Download the produced file automatically +---------------------------------------- + +Use ``php://output`` as the filename. + +.. code-block:: php + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->createSection(); + $section->addText('Hello World!'); + $file = 'HelloWorld.docx'; + header("Content-Description: File Transfer"); + header('Content-Disposition: attachment; filename="' . $file . '"'); + header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); + header('Content-Transfer-Encoding: binary'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Expires: 0'); + $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); + $xmlWriter->save("php://output"); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index abb8777e..6d34ff9f 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -40,6 +40,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [RTF](#rtf) - [HTML](#html) - [PDF](#pdf) +- [Recipes](#recipes) - [Frequently asked questions](#frequently-asked-questions) - [References](#references) @@ -929,6 +930,44 @@ To be completed. To be completed. +# Recipes + +## Create float left image + +Use absolute positioning relative to margin horizontally and to line vertically. + +```php +$imageStyle = array( + 'width' => 40, + 'height' => 40 + 'wrappingStyle' => 'square', + 'positioning' => 'absolute', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'line', +); +$textrun->addImage('resources/_earth.jpg', $imageStyle); +$textrun->addText($lipsumText); +``` + +## Download the produced file automatically + +Use `php://output` as the filename. + +```php +$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$section = $phpWord->createSection(); +$section->addText('Hello World!'); +$file = 'HelloWorld.docx'; +header("Content-Description: File Transfer"); +header('Content-Disposition: attachment; filename="' . $file . '"'); +header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); +header('Content-Transfer-Encoding: binary'); +header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); +header('Expires: 0'); +$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); +$xmlWriter->save("php://output"); +``` + # Frequently asked questions ## Is this the same with PHPWord that I found in CodePlex? From 5ff47f44e982f510b00b4256f985455b077d077c Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 24 May 2014 11:11:12 +0700 Subject: [PATCH 200/326] QA: Misc. bugfixes and docblock improvements --- src/PhpWord/Style/Border.php | 2 +- src/PhpWord/Style/Table.php | 4 ++-- src/PhpWord/Style/TextBox.php | 2 +- src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 4 ++-- tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php | 1 + 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index f0fd8650..84116d7a 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -81,7 +81,7 @@ class Border extends AbstractStyle /** * Get border size * - * @return int[] + * @return integer[] */ public function getBorderSize() { diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 90e8282f..9875cc26 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -192,7 +192,7 @@ class Table extends Border /** * Get TLRBHV Border Size * - * @return int[] + * @return integer[] */ public function getBorderSize() { @@ -430,7 +430,7 @@ class Table extends Border /** * Get cell margin * - * @return int[] + * @return integer[] */ public function getCellMargin() { diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index da19cd10..eb215c06 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -162,7 +162,7 @@ class TextBox extends Image /** * Get cell margin * - * @return int[] + * @return integer[] */ public function getInnerMargin() { diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 23143ef5..88bb0109 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -29,7 +29,7 @@ class MarginBorder extends AbstractStyle /** * Sizes * - * @var int[] + * @var integer[] */ private $sizes = array(); @@ -103,7 +103,7 @@ class MarginBorder extends AbstractStyle /** * Set sizes * - * @param int[] $value + * @param integer[] $value */ public function setSizes($value) { diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index 42c95bcb..f75946cc 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -50,6 +50,7 @@ class ContentTest extends \PHPUnit_Framework_TestCase $phpWord->setDefaultFontName('Verdana'); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $phpWord->addTableStyle('tblStyle', array('width' => 100)); $section = $phpWord->addSection(array('colsNum' => 2)); $section->addText($expected); From 1e9a498ca20f0619fb752b52dbdec4c61bc96cf6 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 24 May 2014 13:48:27 +0700 Subject: [PATCH 201/326] QA: Reduce some complexities: https://scrutinizer-ci.com/g/PHPOffice/PHPWord/code-structure/develop?elementType=operation --- src/PhpWord/Element/AbstractContainer.php | 32 ++---- src/PhpWord/Element/Image.php | 10 +- src/PhpWord/Media.php | 42 +++++--- src/PhpWord/Reader/Word2007/AbstractPart.php | 40 ++++--- src/PhpWord/Shared/Html.php | 4 +- .../Writer/Word2007/Element/TextBreak.php | 6 +- .../Writer/Word2007/Part/Numbering.php | 100 ++++++++++-------- src/PhpWord/Writer/Word2007/Part/Rels.php | 52 +++++---- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 2 +- 9 files changed, 166 insertions(+), 122 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 06a94489..dc87cf18 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -56,38 +56,24 @@ abstract class AbstractContainer extends AbstractElement // Get arguments $args = func_get_args(); - $argsCount = func_num_args(); $withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun')); if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { - $args[3] = null; + $args[3] = null; // Remove paragraph style for texts in textrun } - // Create element dynamically - + // Create element using reflection + $reflection = new \ReflectionClass($elementClass); + $elementArgs = $args; + array_shift($elementArgs); // Shift an element off the beginning of array: the $elementName /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ - if ($argsCount == 2) { // TextRun, TextBox, Table, Footnote, Endnote - $element = new $elementClass($args[1]); - } elseif ($argsCount == 3) { // Object, TextBreak, Title - $element = new $elementClass($args[1], $args[2]); - } elseif ($argsCount == 4) { // PreserveText, Text, Image - $element = new $elementClass($args[1], $args[2], $args[3]); - } elseif ($argsCount == 5) { // CheckBox, Link, ListItemRun, TOC - $element = new $elementClass($args[1], $args[2], $args[3], $args[4]); - } elseif ($argsCount == 6) { // ListItem - $element = new $elementClass($args[1], $args[2], $args[3], $args[4], $args[5]); - } else { // Page Break - $element = new $elementClass(); - } + $element = $reflection->newInstanceArgs($elementArgs); // Set relation Id for media collection $mediaContainer = $this->getMediaContainer(); if (in_array($elementName, array('Link', 'Image', 'Object'))) { - if ($elementName == 'Image') { - /** @var \PhpOffice\PhpWord\Element\Image $element Type hint */ - $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $element); - } else { - $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1]); - } + /** @var \PhpOffice\PhpWord\Element\Image $element Type hint */ + $image = ($elementName == 'Image') ? $element : null; + $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $image); $element->setRelationId($rId); } if ($elementName == 'Object') { diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index c38fda2c..de859ad2 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -284,6 +284,7 @@ class Image extends AbstractElement * * @param bool $base64 * @return string|null + * @since 0.11.0 */ public function getImageStringData($base64 = false) { @@ -291,6 +292,7 @@ class Image extends AbstractElement $actualSource = null; $imageBinary = null; $imageData = null; + $isTemp = false; // Get actual source from archive image or other source // Return null if not found @@ -301,6 +303,7 @@ class Image extends AbstractElement $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { + $isTemp = true; $zip->extractTo(sys_get_temp_dir(), $imageFilename); $actualSource = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $imageFilename; } @@ -313,7 +316,7 @@ class Image extends AbstractElement return null; } - // Read image binary data and convert to hex + // Read image binary data and convert to hex/base64 string if ($this->sourceType == self::SOURCE_GD) { $imageResource = call_user_func($this->imageCreateFunc, $actualSource); ob_start(); @@ -335,6 +338,11 @@ class Image extends AbstractElement } } + // Delete temporary file if necessary + if ($isTemp === true) { + @unlink($actualSource); + } + return $imageData; } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 8cb82013..7f35841c 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -139,37 +139,53 @@ class Media * Get media elements * * @param string $container section|headerx|footerx|footnote|endnote - * @param string $mediaType image|object|link + * @param string $type image|object|link * @return array * @since 0.10.0 */ - public static function getElements($container, $mediaType = null) + public static function getElements($container, $type = null) { - $mediaElements = array(); + $elements = array(); // If header/footer, search for headerx and footerx where x is number if ($container == 'header' || $container == 'footer') { foreach (self::$elements as $key => $val) { if (substr($key, 0, 6) == $container) { - $mediaElements[$key] = $val; + $elements[$key] = $val; } } + return $elements; } else { if (!array_key_exists($container, self::$elements)) { - return $mediaElements; + return $elements; } - foreach (self::$elements[$container] as $mediaKey => $mediaData) { - if (!is_null($mediaType)) { - if ($mediaType == $mediaData['type']) { - $mediaElements[$mediaKey] = $mediaData; - } - } else { - $mediaElements[$mediaKey] = $mediaData; + return self::getElementsByType($container, $type); + } + } + + /** + * Get elements by media type + * + * @param string $container section|footnote|endnote + * @param string $type image|object|link + * @return array + * @since 0.11.0 Splitted from `getElements` to reduce complexity + */ + private static function getElementsByType($container, $type = null) + { + $elements = array(); + + foreach (self::$elements[$container] as $key => $data) { + if ($type !== null) { + if ($type == $data['type']) { + $elements[$key] = $data; } + } else { + $elements[$key] = $data; } } - return $mediaElements; + return $elements; } /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 2936884f..8f14daed 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -453,25 +453,41 @@ abstract class AbstractPart $attribute = ($attribute === null) ? 'w:val' : $attribute; $attributeValue = $xmlReader->getAttribute($attribute, $node); - // Assign style value based on conversion model - if ($method == self::READ_VALUE) { - $styles[$styleProp] = $attributeValue; - } elseif ($method == self::READ_SIZE) { - $styles[$styleProp] = $attributeValue / 2; - } elseif ($method == self::READ_TRUE) { - $styles[$styleProp] = true; - } elseif ($method == self::READ_FALSE) { - $styles[$styleProp] = false; - } elseif ($method == self::READ_EQUAL && $attributeValue == $expected) { - $styles[$styleProp] = true; + $styleValue = $this->readStyleDef($method, $attributeValue, $expected); + if ($styleValue !== null) { + $styles[$styleProp] = $styleValue; } } } - /** @var array $styles Type hint */ return $styles; } + /** + * Return style definition based on conversion method + * + * @param string $method + * @param mixed $attributeValue + * @param mixed $expected + * @return mixed + */ + private function readStyleDef($method, $attributeValue, $expected) + { + $style = $attributeValue; + + if ($method == self::READ_SIZE) { + $style = $attributeValue / 2; + } elseif ($method == self::READ_TRUE) { + $style = true; + } elseif ($method == self::READ_FALSE) { + $style = false; + } elseif ($method == self::READ_EQUAL && $attributeValue == $expected) { + $style = true; + } + + return $style; + } + /** * Returns the target of image, object, or link as stored in ::readMainRels * diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 501d2404..4faacfb1 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -214,7 +214,7 @@ class Html */ case 'li': $cNodes = $node->childNodes; - if (count($cNodes) > 0) { + if ($cNodes->length > 0) { $text = ''; foreach ($cNodes as $cNode) { if ($cNode->nodeName == '#text') { @@ -240,7 +240,7 @@ class Html */ if ($node->nodeName != 'li') { $cNodes = $node->childNodes; - if (count($cNodes) > 0) { + if ($cNodes->length > 0) { foreach ($cNodes as $cNode) { self::parseNode($cNode, $newobject, $styles, $data); } diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 227b1b30..5f4bd3ce 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -37,15 +37,13 @@ class TextBreak extends Text if (!$this->withoutP) { $hasStyle = $element->hasStyle(); + $this->writeOpeningWP(); if ($hasStyle) { - $this->writeOpeningWP(); $xmlWriter->startElement('w:pPr'); $this->writeFontStyle(); $xmlWriter->endElement(); // w:pPr - $this->writeClosingWP(); - } else { - $xmlWriter->writeElement('w:p'); } + $this->writeClosingWP(); } else { $xmlWriter->writeElement('w:br'); } diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 2678ac55..df5abd9b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -24,6 +24,8 @@ use PhpOffice\PhpWord\Style\NumberingLevel; /** * Word2007 numbering part writer: word/numbering.xml + * + * @since 0.10.0 */ class Numbering extends AbstractPart { @@ -97,12 +99,6 @@ class Numbering extends AbstractPart */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) { - $tabPos = $level->getTabPos(); - $left = $level->getLeft(); - $hanging = $level->getHanging(); - $font = $level->getFont(); - $hint = $level->getHint(); - $xmlWriter->startElement('w:lvl'); $xmlWriter->writeAttribute('w:ilvl', $level->getLevel()); @@ -124,48 +120,64 @@ class Numbering extends AbstractPart } } - // Paragraph styles - if (!is_null($tabPos) || !is_null($left) || !is_null($hanging)) { - $xmlWriter->startElement('w:pPr'); - if (!is_null($tabPos)) { - $xmlWriter->startElement('w:tabs'); - $xmlWriter->startElement('w:tab'); - $xmlWriter->writeAttribute('w:val', 'num'); - $xmlWriter->writeAttribute('w:pos', $tabPos); - $xmlWriter->endElement(); // w:tab - $xmlWriter->endElement(); // w:tabs - } - if (!is_null($left) || !is_null($hanging)) { - $xmlWriter->startElement('w:ind'); - if (!is_null($left)) { - $xmlWriter->writeAttribute('w:left', $left); - } - if (!is_null($hanging)) { - $xmlWriter->writeAttribute('w:hanging', $hanging); - } - $xmlWriter->endElement(); // w:ind - } - $xmlWriter->endElement(); // w:pPr - } + // Paragraph & font styles + $this->writeParagraph($xmlWriter, $level); + $this->writeFont($xmlWriter, $level); - // Font styles - if (!is_null($font) || !is_null($hint)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rFonts'); - if (!is_null($font)) { - $xmlWriter->writeAttribute('w:ascii', $font); - $xmlWriter->writeAttribute('w:hAnsi', $font); - $xmlWriter->writeAttribute('w:cs', $font); - } - if (!is_null($hint)) { - $xmlWriter->writeAttribute('w:hint', $hint); - } - $xmlWriter->endElement(); // w:rFonts - $xmlWriter->endElement(); // w:rPr - } $xmlWriter->endElement(); // w:lvl } + /** + * Write level paragraph + * + * @since 0.11.0 + * @todo Use paragraph style writer + */ + private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) + { + $tabPos = $level->getTabPos(); + $left = $level->getLeft(); + $hanging = $level->getHanging(); + + $xmlWriter->startElement('w:pPr'); + + $xmlWriter->startElement('w:tabs'); + $xmlWriter->startElement('w:tab'); + $xmlWriter->writeAttribute('w:val', 'num'); + $xmlWriter->writeAttributeIf($tabPos !== null, 'w:pos', $tabPos); + $xmlWriter->writeAttribute('w:pos', $tabPos); + $xmlWriter->endElement(); // w:tab + $xmlWriter->endElement(); // w:tabs + + $xmlWriter->startElement('w:ind'); + $xmlWriter->writeAttributeIf($left !== null, 'w:left', $left); + $xmlWriter->writeAttributeIf($hanging !== null, 'w:hanging', $hanging); + $xmlWriter->endElement(); // w:ind + + $xmlWriter->endElement(); // w:pPr + } + + /** + * Write level font + * + * @since 0.11.0 + * @todo Use font style writer + */ + private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level) + { + $font = $level->getFont(); + $hint = $level->getHint(); + + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rFonts'); + $xmlWriter->writeAttributeIf($font !== null, 'w:ascii', $font); + $xmlWriter->writeAttributeIf($font !== null, 'w:hAnsi', $font); + $xmlWriter->writeAttributeIf($font !== null, 'w:cs', $font); + $xmlWriter->writeAttributeIf($hint !== null, 'w:hint', $hint); + $xmlWriter->endElement(); // w:rFonts + $xmlWriter->endElement(); // w:rPr + } + /** * Get random hexadecimal number value * diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index c1405258..562deb35 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -50,43 +50,51 @@ class Rels extends AbstractPart * Write relationships * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param null|array $xmlRels - * @param null|array $mediaRels - * @param integer $relId + * @param array $xmlRels + * @param array $mediaRels + * @param int $relId */ - protected function writeRels(XMLWriter $xmlWriter, $xmlRels = null, $mediaRels = null, $relId = 1) + protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRels = array(), $relId = 1) { $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // XML files relationships - if (is_array($xmlRels)) { - foreach ($xmlRels as $target => $type) { - $this->writeRel($xmlWriter, $relId++, $type, $target); - } + foreach ($xmlRels as $target => $type) { + $this->writeRel($xmlWriter, $relId++, $type, $target); } // Media relationships - if (is_array($mediaRels)) { - $typePrefix = 'officeDocument/2006/relationships/'; - $typeMapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'); - $targetPaths = array('image' => 'media/', 'object' => 'embeddings/'); - - foreach ($mediaRels as $mediaRel) { - $mediaType = $mediaRel['type']; - $type = array_key_exists($mediaType, $typeMapping) ? $typeMapping[$mediaType] : $mediaType; - $target = array_key_exists($mediaType, $targetPaths) ? $targetPaths[$mediaType] : ''; - $target .= $mediaRel['target']; - $targetMode = ($type == 'hyperlink') ? 'External' : ''; - - $this->writeRel($xmlWriter, $relId++, $typePrefix . $type, $target, $targetMode); - } + foreach ($mediaRels as $mediaRel) { + $this->writeMediaRel($xmlWriter, $relId++, $mediaRel); } $xmlWriter->endElement(); // Relationships } + /** + * Write media relationships + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param int $relId + * @param array $mediaRel + */ + private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) + { + $typePrefix = 'officeDocument/2006/relationships/'; + $typeMapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'); + $targetMapping = array('image' => 'media/', 'object' => 'embeddings/'); + + $mediaType = $mediaRel['type']; + $type = array_key_exists($mediaType, $typeMapping) ? $typeMapping[$mediaType] : $mediaType; + $targetPrefix = array_key_exists($mediaType, $targetMapping) ? $targetMapping[$mediaType] : ''; + $target = $mediaRel['target']; + $targetMode = ($type == 'hyperlink') ? 'External' : ''; + + $this->writeRel($xmlWriter, $relId, $typePrefix . $type, $targetPrefix . $target, $targetMode); + } + /** * Write individual rels entry * diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index a3697834..627a2bcd 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -39,7 +39,7 @@ class RelsPart extends Rels public function write() { $xmlWriter = $this->getXmlWriter(); - $this->writeRels($xmlWriter, null, $this->media); + $this->writeRels($xmlWriter, array(), $this->media); return $xmlWriter->getData(); } From dc6c487cd02afbf135463db364f61f768afa6597 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 24 May 2014 23:07:34 +0700 Subject: [PATCH 202/326] Fix test error --- src/PhpWord/Element/Image.php | 10 +++++++--- src/PhpWord/Settings.php | 2 +- src/PhpWord/Shared/Html.php | 4 ++-- src/PhpWord/Writer/Word2007/Part/Numbering.php | 1 - tests/PhpWord/Tests/Element/ImageTest.php | 1 + tests/PhpWord/Tests/Element/SectionTest.php | 2 +- tests/PhpWord/Tests/SettingsTest.php | 2 +- 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index de859ad2..a1cb8250 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -312,9 +312,13 @@ class Image extends AbstractElement } else { $actualSource = $source; } - if ($actualSource === null) { - return null; - } + + // Can't find any case where $actualSource = null hasn't captured by + // preceding exceptions. Please uncomment when you find the case and + // put the case into Element\ImageTest. + // if ($actualSource === null) { + // return null; + // } // Read image binary data and convert to hex/base64 string if ($this->sourceType == self::SOURCE_GD) { diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 8d9e2ace..cb74389a 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -344,7 +344,7 @@ class Settings // Parse config file $config = array(); if ($configFile !== null) { - $config = parse_ini_file($configFile); + $config = @parse_ini_file($configFile); if ($config === false) { return $config; } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 4faacfb1..501d2404 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -214,7 +214,7 @@ class Html */ case 'li': $cNodes = $node->childNodes; - if ($cNodes->length > 0) { + if (count($cNodes) > 0) { $text = ''; foreach ($cNodes as $cNode) { if ($cNode->nodeName == '#text') { @@ -240,7 +240,7 @@ class Html */ if ($node->nodeName != 'li') { $cNodes = $node->childNodes; - if ($cNodes->length > 0) { + if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { self::parseNode($cNode, $newobject, $styles, $data); } diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index df5abd9b..05cbf7b9 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -145,7 +145,6 @@ class Numbering extends AbstractPart $xmlWriter->startElement('w:tab'); $xmlWriter->writeAttribute('w:val', 'num'); $xmlWriter->writeAttributeIf($tabPos !== null, 'w:pos', $tabPos); - $xmlWriter->writeAttribute('w:pos', $tabPos); $xmlWriter->endElement(); // w:tab $xmlWriter->endElement(); // w:tabs diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index b04b5fe6..11b33d87 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -38,6 +38,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getSource(), $src); $this->assertEquals($oImage->getMediaId(), md5($src)); $this->assertEquals($oImage->isWatermark(), false); + $this->assertEquals($oImage->getSourceType(), Image::SOURCE_LOCAL); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } diff --git a/tests/PhpWord/Tests/Element/SectionTest.php b/tests/PhpWord/Tests/Element/SectionTest.php index 271e81e3..af7595e2 100644 --- a/tests/PhpWord/Tests/Element/SectionTest.php +++ b/tests/PhpWord/Tests/Element/SectionTest.php @@ -73,7 +73,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase { $expected = 'landscape'; $object = new Section(0); - $object->setSettings(array('orientation' => $expected)); + $object->setSettings(array('orientation' => $expected, 'foo' => null)); $this->assertEquals($expected, $object->getSettings()->getOrientation()); } diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index 36565eb1..61364034 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -111,6 +111,6 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../../phpword.ini.dist')); // Test with invalid file - $this->assertEmpty(Settings::loadConfig(__DIR__ . '/files/xsl/passthrough.xsl')); + $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../../phpunit.xml.dist')); } } From 92c7a24c38ebeb1bf90c38d0fe989b0bde2f12a7 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 25 May 2014 22:51:14 +0700 Subject: [PATCH 203/326] QA: Additional unit tests and docblock fixes --- CHANGELOG.md | 1 + src/PhpWord/Autoloader.php | 1 + src/PhpWord/DocumentProperties.php | 2 +- src/PhpWord/Shared/XMLWriter.php | 10 +- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Cell.php | 2 +- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Style/LineNumbering.php | 3 +- src/PhpWord/Style/ListItem.php | 4 +- src/PhpWord/Style/Paragraph.php | 10 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Style/TextBox.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 37 +++- src/PhpWord/Writer/HTML.php | 30 ++- src/PhpWord/Writer/PDF.php | 8 +- src/PhpWord/Writer/PDF/DomPDF.php | 2 +- src/PhpWord/Writer/PDF/MPDF.php | 2 +- src/PhpWord/Writer/PDF/TCPDF.php | 2 +- src/PhpWord/Writer/RTF.php | 38 ++-- src/PhpWord/Writer/Word2007/Part/Styles.php | 205 ++++++++++-------- tests/PhpWord/Tests/Shared/XMLWriterTest.php | 40 ++++ .../PhpWord/Tests/Style/AbstractStyleTest.php | 1 + tests/PhpWord/Tests/Style/CellTest.php | 4 + tests/PhpWord/Tests/Style/FontTest.php | 1 + tests/PhpWord/Tests/Style/ParagraphTest.php | 14 ++ tests/PhpWord/Tests/Style/TableTest.php | 4 + .../Tests/_files/documents/reader.docx | Bin 74101 -> 74121 bytes 27 files changed, 290 insertions(+), 139 deletions(-) create mode 100644 tests/PhpWord/Tests/Shared/XMLWriterTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 84cc2cb1..fcaf1388 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r - `Writer\Word2007\Part`: `Numbering::writeNumbering()`, `Settings::writeSettings()`, `WebSettings::writeWebSettings()`, `ContentTypes::writeContentTypes()`, `Styles::writeStyles()`, `Document::writeDocument()` all changed into `write()` - `Writer\Word2007\Part\DocProps`: Split into `Writer\Word2007\Part\DocPropsCore` and `Writer\Word2007\Part\DocPropsApp` - `Element\Title::getBookmarkId()` replaced by `Element\Title::getRelationId()` +- `Writer\HTML::writeDocument`: Replaced by `Writer\HTML::getContent` ### Miscellaneous diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index c60ae9a6..c467f836 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -22,6 +22,7 @@ namespace PhpOffice\PhpWord; */ class Autoloader { + /** @const string */ const NAMESPACE_PREFIX = 'PhpOffice\\PhpWord\\'; /** diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 95159ec0..5644c3d9 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -22,7 +22,7 @@ namespace PhpOffice\PhpWord; */ class DocumentProperties { - /** Constants */ + /** @const string Property type constants */ const PROPERTY_TYPE_BOOLEAN = 'b'; const PROPERTY_TYPE_INTEGER = 'i'; const PROPERTY_TYPE_FLOAT = 'f'; diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index dc85bfc1..81e8e286 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -68,9 +68,8 @@ class XMLWriter // Create temporary filename $this->tempFile = @tempnam($tempFolder, 'xml'); - // Open storage + // Fallback to memory when temporary file cannot be used if ($this->xmlWriter->openUri($this->tempFile) === false) { - // Fallback to memory... $this->xmlWriter->openMemory(); } } @@ -105,9 +104,16 @@ class XMLWriter * * @param mixed $function * @param mixed $args + * @throws \BadMethodCallException */ public function __call($function, $args) { + // Catch exception + if (method_exists($this->xmlWriter, $function) === false) { + throw new \BadMethodCallException("Method '{$function}' does not exists."); + } + + // Run method try { @call_user_func_array(array($this->xmlWriter, $function), $args); } catch (\Exception $ex) { diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 1b916934..8167c4d2 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -265,7 +265,7 @@ abstract class AbstractStyle { if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) { throw new \InvalidArgumentException('Invalid style value.'); - } elseif (is_null($value) || trim($value) == '') { + } elseif ($value === null || trim($value) == '') { $value = $default; } diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 95ed13b4..2d1b88d0 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -144,7 +144,7 @@ class Cell extends Border */ public function getBgColor() { - if (!is_null($this->shading)) { + if ($this->shading !== null) { return $this->shading->getFill(); } else { return null; diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 07eebdb2..0775b8b3 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -540,7 +540,7 @@ class Font extends AbstractStyle */ public function getBgColor() { - if (!is_null($this->shading)) { + if ($this->shading !== null) { return $this->shading->getFill(); } else { return null; diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index d49c7f4e..b93ce03f 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -20,11 +20,12 @@ namespace PhpOffice\PhpWord\Style; /** * Line numbering style * - * @link http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html + * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html * @since 0.10.0 */ class LineNumbering extends AbstractStyle { + /** @const string Line numbering restart setting http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */ const LINE_NUMBERING_CONTINUOUS = 'continuous'; const LINE_NUMBERING_NEW_PAGE = 'newPage'; const LINE_NUMBERING_NEW_SECTION = 'newSection'; diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 554d75b0..a689c691 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -65,7 +65,7 @@ class ListItem extends AbstractStyle */ public function __construct($numStyle = null) { - if (!is_null($numStyle)) { + if ($numStyle !== null) { $this->setNumStyle($numStyle); } else { $this->setListType(); @@ -149,7 +149,7 @@ class ListItem extends AbstractStyle { // Check if legacy style already registered in global Style collection $numStyle = "PHPWordList{$this->listType}"; - if (!is_null(Style::getStyle($numStyle))) { + if (Style::getStyle($numStyle) !== null) { $this->setNumStyle($numStyle); return; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 8609b5ab..e70833ca 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -171,7 +171,7 @@ class Paragraph extends AbstractStyle */ public function getSpaceBefore() { - if (!is_null($this->spacing)) { + if ($this->spacing !== null) { return $this->spacing->getBefore(); } else { return null; @@ -196,7 +196,7 @@ class Paragraph extends AbstractStyle */ public function getSpaceAfter() { - if (!is_null($this->spacing)) { + if ($this->spacing !== null) { return $this->spacing->getAfter(); } else { return null; @@ -221,7 +221,7 @@ class Paragraph extends AbstractStyle */ public function getSpacing() { - if (!is_null($this->spacing)) { + if ($this->spacing !== null) { return $this->spacing->getLine(); } else { return null; @@ -278,7 +278,7 @@ class Paragraph extends AbstractStyle */ public function getIndent() { - if (!is_null($this->indentation)) { + if ($this->indentation !== null) { return $this->indentation->getLeft(); } else { return null; @@ -303,7 +303,7 @@ class Paragraph extends AbstractStyle */ public function getHanging() { - if (!is_null($this->indentation)) { + if ($this->indentation !== null) { return $this->indentation->getHanging(); } else { return null; diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 9875cc26..24f50667 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -169,7 +169,7 @@ class Table extends Border */ public function getBgColor() { - if (!is_null($this->shading)) { + if ($this->shading !== null) { return $this->shading->getFill(); } diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index eb215c06..9f0a1dde 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -179,7 +179,7 @@ class TextBox extends Image $hasInnerMargins = false; $margins = $this->getInnerMargin(); for ($i = 0; $i < count($margins); $i++) { - if (!is_null($margins[$i])) { + if ($margins[$i] !== null) { $hasInnerMargins = true; } } diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 52a1a28c..367b7729 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -258,7 +258,7 @@ abstract class AbstractWriter implements WriterInterface * * @param string $filename * @return \PhpOffice\PhpWord\Shared\ZipArchive - * @throws \PhpOffice\PhpWord\Exception\Exception + * @throws \Exception */ protected function getZipArchive($filename) { @@ -271,13 +271,46 @@ abstract class AbstractWriter implements WriterInterface $zip = new ZipArchive(); if ($zip->open($filename, ZipArchive::OVERWRITE) !== true) { if ($zip->open($filename, ZipArchive::CREATE) !== true) { - throw new Exception("Could not open " . $filename . " for writing."); + throw new \Exception("Could not open '{$filename}' for writing."); } } return $zip; } + /** + * Open file for writing + * + * @param string $filename + * @return resource + * @throws \Exception + * @since 0.11.0 + */ + protected function openFile($filename) + { + $filename = $this->getTempFile($filename); + $fileHandle = fopen($filename, 'w'); + if ($fileHandle === false) { + throw new \Exception("Could not open '{$filename}' for writing."); + } + + return $fileHandle; + } + + /** + * Write content to file + * + * @param resource $fileHandle + * @param string $content + * @since 0.11.0 + */ + protected function writeFile(&$fileHandle, $content) + { + fwrite($fileHandle, $content); + fclose($fileHandle); + $this->cleanupTempFile(); + } + /** * Add files to package * diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 88e7658d..29173ff2 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; /** @@ -69,25 +68,20 @@ class HTML extends AbstractWriter implements WriterInterface */ public function save($filename = null) { - $this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/'); - $hFile = fopen($filename, 'w'); - if ($hFile !== false) { - fwrite($hFile, $this->writeDocument()); - fclose($hFile); - } else { - throw new Exception("Can't open file"); - } - $this->clearTempDir(); + $fileHandle = $this->openFile($filename); + $this->writeFile($fileHandle, $this->getContent()); } /** - * Get phpWord data + * Get content * * @return string + * @since 0.11.0 */ - public function writeDocument() + public function getContent() { $content = ''; + $content .= '' . PHP_EOL; $content .= '' . PHP_EOL; $content .= '' . PHP_EOL; @@ -128,4 +122,16 @@ class HTML extends AbstractWriter implements WriterInterface { $this->notes[$noteId] = $noteMark; } + + /** + * Write document + * + * @return string + * @deprecated 0.11.0 + * @codeCoverageIgnore + */ + public function writeDocument() + { + return $this->getContent(); + } } diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 98dc1220..17865563 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -65,13 +65,13 @@ class PDF * @param string $name Renderer library method name * @param mixed[] $arguments Array of arguments to pass to the renderer method * @return mixed Returned data from the PDF renderer wrapper method - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __call($name, $arguments) { - if ($this->renderer === null) { - throw new Exception("PDF Rendering library has not been defined."); - } + // Note: Commented because all exceptions should already be catched by `__construct` + // if ($this->renderer === null) { + // throw new Exception("PDF Rendering library has not been defined."); + // } return call_user_func_array(array($this->renderer, $name), $arguments); } diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 4effc154..a40e2cea 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -50,7 +50,7 @@ class DomPDF extends AbstractRenderer implements WriterInterface // Create PDF $pdf = new \DOMPDF(); $pdf->set_paper(strtolower($paperSize), $orientation); - $pdf->load_html($this->writeDocument()); + $pdf->load_html($this->getContent()); $pdf->render(); // Write to file diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index d38d5b66..9d4e050c 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -61,7 +61,7 @@ class MPDF extends AbstractRenderer implements WriterInterface $pdf->setKeywords($docProps->getKeywords()); $pdf->setCreator($docProps->getCreator()); - $pdf->writeHTML($this->writeDocument()); + $pdf->writeHTML($this->getContent()); // Write to file fwrite($fileHandle, $pdf->output($filename, 'S')); diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 05f02756..669a2cdd 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -54,7 +54,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface $pdf->setPrintFooter(false); $pdf->addPage(); $pdf->setFont($this->getFont()); - $pdf->writeHTML($this->writeDocument()); + $pdf->writeHTML($this->getContent()); // Write document properties $phpWord = $this->getPhpWord(); diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index ef94b264..d7fed942 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; /** @@ -56,29 +55,34 @@ class RTF extends AbstractWriter implements WriterInterface } /** - * Save PhpWord to file + * Save content to file * * @param string $filename * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) { - $content = ''; - $filename = $this->getTempFile($filename); - $hFile = fopen($filename, 'w'); - if ($hFile !== false) { - $content .= '{'; - $content .= '\rtf1' . PHP_EOL; - $content .= $this->getWriterPart('Header')->write(); - $content .= $this->getWriterPart('Document')->write(); - $content .= '}'; + $fileHandle = $this->openFile($filename); + $this->writeFile($fileHandle, $this->getContent()); + } - fwrite($hFile, $content); - fclose($hFile); - } else { - throw new Exception("Can't open file"); - } - $this->cleanupTempFile(); + /** + * Get content + * + * @return string + * @since 0.11.0 + */ + private function getContent() + { + $content = ''; + + $content .= '{'; + $content .= '\rtf1' . PHP_EOL; + $content .= $this->getWriterPart('Header')->write(); + $content .= $this->getWriterPart('Document')->write(); + $content .= '}'; + + return $content; } /** diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index a0a6317a..0d688e36 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -20,9 +20,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Settings as PhpWordSettings; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Style\Font as FontStyle; +use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; +use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter; @@ -31,6 +31,7 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter; * Word2007 styles part writer: word/styles.xml * * @todo Do something with the numbering style introduced in 0.10.0 + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For writeFontStyle, writeParagraphStyle, and writeTableStyle */ class Styles extends AbstractPart { @@ -59,88 +60,11 @@ class Styles extends AbstractPart continue; } - // Font style - if ($style instanceof Font) { - $paragraphStyle = $style->getParagraph(); - $styleType = $style->getStyleType(); - $type = ($styleType == 'title') ? 'paragraph' : 'character'; - if (!is_null($paragraphStyle)) { - $type = 'paragraph'; - } - - $xmlWriter->startElement('w:style'); - $xmlWriter->writeAttribute('w:type', $type); - if ($styleType == 'title') { - $arrStyle = explode('_', $styleName); - $styleId = 'Heading' . $arrStyle[1]; - $styleName = 'heading ' . $arrStyle[1]; - $styleLink = 'Heading' . $arrStyle[1] . 'Char'; - $xmlWriter->writeAttribute('w:styleId', $styleId); - - $xmlWriter->startElement('w:link'); - $xmlWriter->writeAttribute('w:val', $styleLink); - $xmlWriter->endElement(); - } - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', $styleName); - $xmlWriter->endElement(); - - // Parent style - $xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal'); - - // w:pPr - if (!is_null($paragraphStyle)) { - $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle); - $styleWriter->write(); - } - - // w:rPr - $styleWriter = new FontStyleWriter($xmlWriter, $style); - $styleWriter->write(); - - $xmlWriter->endElement(); - - // Paragraph style - } elseif ($style instanceof Paragraph) { - $xmlWriter->startElement('w:style'); - $xmlWriter->writeAttribute('w:type', 'paragraph'); - $xmlWriter->writeAttribute('w:customStyle', '1'); - $xmlWriter->writeAttribute('w:styleId', $styleName); - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', $styleName); - $xmlWriter->endElement(); - - // Parent style - $basedOn = $style->getBasedOn(); - $xmlWriter->writeElementIf(!is_null($basedOn), 'w:basedOn', 'w:val', $basedOn); - - // Next paragraph style - $next = $style->getNext(); - $xmlWriter->writeElementIf(!is_null($next), 'w:next', 'w:val', $next); - - // w:pPr - $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); - $styleWriter->write(); - - $xmlWriter->endElement(); - - // Table style - } elseif ($style instanceof Table) { - $xmlWriter->startElement('w:style'); - $xmlWriter->writeAttribute('w:type', 'table'); - $xmlWriter->writeAttribute('w:customStyle', '1'); - $xmlWriter->writeAttribute('w:styleId', $styleName); - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', $styleName); - $xmlWriter->endElement(); - $xmlWriter->startElement('w:uiPriority'); - $xmlWriter->writeAttribute('w:val', '99'); - $xmlWriter->endElement(); - - $styleWriter = new TableStyleWriter($xmlWriter, $style); - $styleWriter->write(); - - $xmlWriter->endElement(); // w:style + // Get style class and execute if the private method exists + $styleClass = substr(get_class($style), strrpos(get_class($style), '\\') + 1); + $method = "write{$styleClass}Style"; + if (method_exists($this, $method)) { + $this->$method($xmlWriter, $styleName, $style); } } } @@ -213,4 +137,115 @@ class Styles extends AbstractPart $xmlWriter->endElement(); // w:style } } + + /** + * Write font style + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $styleName + * @param \PhpOffice\PhpWord\Style\Font $style + */ + private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style) + { + $paragraphStyle = $style->getParagraph(); + $styleType = $style->getStyleType(); + $type = ($styleType == 'title') ? 'paragraph' : 'character'; + if (!is_null($paragraphStyle)) { + $type = 'paragraph'; + } + + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', $type); + + // Heading style + if ($styleType == 'title') { + $arrStyle = explode('_', $styleName); + $styleId = 'Heading' . $arrStyle[1]; + $styleName = 'heading ' . $arrStyle[1]; + $styleLink = 'Heading' . $arrStyle[1] . 'Char'; + $xmlWriter->writeAttribute('w:styleId', $styleId); + + $xmlWriter->startElement('w:link'); + $xmlWriter->writeAttribute('w:val', $styleLink); + $xmlWriter->endElement(); + } + + // Style name + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', $styleName); + $xmlWriter->endElement(); + + // Parent style + $xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal'); + + // w:pPr + if (!is_null($paragraphStyle)) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle); + $styleWriter->write(); + } + + // w:rPr + $styleWriter = new FontStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $xmlWriter->endElement(); + } + + /** + * Write paragraph style + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $styleName + * @param \PhpOffice\PhpWord\Style\Paragraph $style + */ + private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style) + { + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', 'paragraph'); + $xmlWriter->writeAttribute('w:customStyle', '1'); + $xmlWriter->writeAttribute('w:styleId', $styleName); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', $styleName); + $xmlWriter->endElement(); + + // Parent style + $basedOn = $style->getBasedOn(); + $xmlWriter->writeElementIf(!is_null($basedOn), 'w:basedOn', 'w:val', $basedOn); + + // Next paragraph style + $next = $style->getNext(); + $xmlWriter->writeElementIf(!is_null($next), 'w:next', 'w:val', $next); + + // w:pPr + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $xmlWriter->endElement(); + } + + /** + * Write table style + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $styleName + * @param \PhpOffice\PhpWord\Style\Table $style + */ + private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style) + { + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', 'table'); + $xmlWriter->writeAttribute('w:customStyle', '1'); + $xmlWriter->writeAttribute('w:styleId', $styleName); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', $styleName); + $xmlWriter->endElement(); + $xmlWriter->startElement('w:uiPriority'); + $xmlWriter->writeAttribute('w:val', '99'); + $xmlWriter->endElement(); + + $styleWriter = new TableStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $xmlWriter->endElement(); // w:style + } } diff --git a/tests/PhpWord/Tests/Shared/XMLWriterTest.php b/tests/PhpWord/Tests/Shared/XMLWriterTest.php new file mode 100644 index 00000000..08db3918 --- /dev/null +++ b/tests/PhpWord/Tests/Shared/XMLWriterTest.php @@ -0,0 +1,40 @@ +foo(); + } +} diff --git a/tests/PhpWord/Tests/Style/AbstractStyleTest.php b/tests/PhpWord/Tests/Style/AbstractStyleTest.php index 15ff8fac..d35e1090 100644 --- a/tests/PhpWord/Tests/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Tests/Style/AbstractStyleTest.php @@ -45,6 +45,7 @@ class AbstractStyleTest extends \PHPUnit_Framework_TestCase $this->assertEquals(true, self::callProtectedMethod($stub, 'setBoolVal', array(true, false))); $this->assertEquals(12, self::callProtectedMethod($stub, 'setIntVal', array(12, 200))); $this->assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', array(871.1, 2.1))); + $this->assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', array('871.1', 2.1))); $this->assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', array('a', array('a', 'b'), 'b'))); } diff --git a/tests/PhpWord/Tests/Style/CellTest.php b/tests/PhpWord/Tests/Style/CellTest.php index 1a026710..f9131728 100644 --- a/tests/PhpWord/Tests/Style/CellTest.php +++ b/tests/PhpWord/Tests/Style/CellTest.php @@ -52,7 +52,11 @@ class CellTest extends \PHPUnit_Framework_TestCase foreach ($attributes as $key => $value) { $set = "set{$key}"; $get = "get{$key}"; + + $this->assertNull($object->$get()); // Init with null value + $object->$set($value); + $this->assertEquals($value, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index ca2105fb..432b29fb 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -74,6 +74,7 @@ class FontTest extends \PHPUnit_Framework_TestCase ); foreach ($attributes as $key => $default) { $get = is_bool($default) ? "is{$key}" : "get{$key}"; + $this->assertEquals($default, $object->$get()); $object->setStyleValue("$key", null); $this->assertEquals($default, $object->$get()); $object->setStyleValue("$key", ''); diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 357371c6..32e46985 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -96,6 +96,20 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase } } + /** + * Test get null style value + */ + public function testGetNullStyleValue() + { + $object = new Paragraph(); + + $attributes = array('spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter'); + foreach ($attributes as $key) { + $get = "get{$key}"; + $this->assertNull($object->$get()); + } + } + /** * Test tabs */ diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index a7b46c1f..2afbab74 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -74,6 +74,9 @@ class TableTest extends \PHPUnit_Framework_TestCase 'cellMarginLeft' => 240, 'cellMarginRight' => 240, 'cellMarginBottom' => 240, + 'align' => 'center', + 'width' => 100, + 'unit' => 'pct', ); foreach ($attributes as $key => $value) { $set = "set{$key}"; @@ -146,6 +149,7 @@ class TableTest extends \PHPUnit_Framework_TestCase $this->assertEquals($value, $object->$get()); } $this->assertEquals($values, $object->getCellMargin()); + $this->assertTrue($object->hasMargin()); } /** diff --git a/tests/PhpWord/Tests/_files/documents/reader.docx b/tests/PhpWord/Tests/_files/documents/reader.docx index 5f37ef4b17d05dc992c92922b5591eb978a429a8..d09091b11983772d56172c519b702ede44df8989 100644 GIT binary patch delta 2647 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 From d9a2c4c3ca235c20adc7c9bf75b108b5f9b75786 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 27 May 2014 00:46:18 +0700 Subject: [PATCH 204/326] Bugfix #248: Image: `marginLeft` and `marginTop` cannot accept float value --- CHANGELOG.md | 1 + src/PhpWord/Style/Image.php | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcaf1388..41f0c3ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r - Header: All images added to the second header were assigned to the first header - @basjan GH-222 - Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan GH-233 GH-234 - PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin GH-150 +- Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin GH-248 ### Deprecated diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 33c85ddf..f816b32f 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -102,14 +102,14 @@ class Image extends AbstractStyle /** * Margin Top * - * @var int + * @var int|float */ private $marginTop = 0; /** * Margin Left * - * @var int + * @var int|float */ private $marginLeft = 0; @@ -235,7 +235,7 @@ class Image extends AbstractStyle /** * Get margin top * - * @return int + * @return int|float */ public function getMarginTop() { @@ -245,12 +245,12 @@ class Image extends AbstractStyle /** * Set margin top * - * @param int $value + * @param int|float $value * @return self */ public function setMarginTop($value = 0) { - $this->marginTop = $this->setIntVal($value, 0); + $this->marginTop = $this->setFloatVal($value, 0); return $this; } @@ -258,7 +258,7 @@ class Image extends AbstractStyle /** * Get margin left * - * @return int + * @return int|float */ public function getMarginLeft() { @@ -268,12 +268,12 @@ class Image extends AbstractStyle /** * Set margin left * - * @param int $value + * @param int|float $value * @return self */ public function setMarginLeft($value = 0) { - $this->marginLeft = $this->setIntVal($value, 0); + $this->marginLeft = $this->setFloatVal($value, 0); return $this; } From d7f3d25b2aa8e81ff6a8a65a71437f562dace15c Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 27 May 2014 01:08:54 +0700 Subject: [PATCH 205/326] #248 More flexible checking for float value --- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Image.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 8167c4d2..13ef8f9b 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -245,7 +245,7 @@ abstract class AbstractStyle if (is_string($value) && (preg_match('/[^\d\.\,]/', $value) == 0)) { $value = floatval($value); } - if (!is_float($value)) { + if (!is_numeric($value)) { $value = $default; } diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index f816b32f..1de51870 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -250,7 +250,7 @@ class Image extends AbstractStyle */ public function setMarginTop($value = 0) { - $this->marginTop = $this->setFloatVal($value, 0); + $this->marginTop = $this->setNumericVal($value, 0); return $this; } @@ -273,7 +273,7 @@ class Image extends AbstractStyle */ public function setMarginLeft($value = 0) { - $this->marginLeft = $this->setFloatVal($value, 0); + $this->marginLeft = $this->setNumericVal($value, 0); return $this; } From 88f65184060e8d4e33c5bd8c5fadac8c1b271dfe Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 28 May 2014 07:42:50 +0700 Subject: [PATCH 206/326] Init VERSION and improve requirement checking --- VERSION | 1 + samples/Sample_Header.php | 4 ++-- samples/index.php | 36 +++++++++++++++++++++++------------- 3 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..142464bf --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.11.0 \ No newline at end of file diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index b752848d..f39bda16 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -6,13 +6,13 @@ use PhpOffice\PhpWord\Autoloader; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\IOFactory; -error_reporting(E_ALL & ~E_DEPRECATED); +error_reporting(E_ALL); define('CLI', (PHP_SAPI == 'cli') ? true : false); define('EOL', CLI ? PHP_EOL : '
    '); define('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php')); define('IS_INDEX', SCRIPT_FILENAME == 'index'); -require_once '../src/PhpWord/Autoloader.php'; +require_once __DIR__ . '/../src/PhpWord/Autoloader.php'; Autoloader::register(); Settings::loadConfig(); diff --git a/samples/index.php b/samples/index.php index 94b98901..420c5420 100644 --- a/samples/index.php +++ b/samples/index.php @@ -1,5 +1,13 @@ array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), + 'xml' => array('PHP extension XML', extension_loaded('xml')), + 'zip' => array('PHP extension ZipArchive (optional)', extension_loaded('zip')), + 'gd' => array('PHP extension GD (optional)', extension_loaded('gd')), + 'xmlw' => array('PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')), + 'xsl' => array('PHP extension XSL (optional)', extension_loaded('xsl')), +); if (!CLI) { ?>
    @@ -11,20 +19,22 @@ if (!CLI) {

    array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), - 'zip' => array('PHP extension ZipArchive', extension_loaded('zip')), - 'xml' => array('PHP extension XML', extension_loaded('xml')), - 'gd' => array('PHP extension GD (optional)', extension_loaded('gd')), -); -echo "

    Requirements

    "; -echo "
      "; -foreach ($requirements as $key => $value) { - $status = $value[1] ? 'passed' : 'failed'; - echo "
    • {$value[0]} ... {$status}
    • "; -} -echo "
    "; } if (!CLI) { + echo "

    Requirement check:

    "; + echo "
      "; + foreach ($requirements as $key => $value) { + list($label, $result) = $value; + $status = $result ? 'passed' : 'failed'; + echo "
    • {$label} ... {$status}
    • "; + } + echo "
    "; include_once 'Sample_Footer.php'; +} else { + echo 'Requirement check:' . PHP_EOL; + foreach ($requirements as $key => $value) { + list($label, $result) = $value; + $status = $result ? '32m passed' : '31m failed'; + echo "{$label} ... \033[{$status}\033[0m" . PHP_EOL; + } } From 8ab6f64addc3d6431aa54f49d28bd0d280f78ada Mon Sep 17 00:00:00 2001 From: Zachary Rankin Date: Tue, 27 May 2014 22:05:34 -0700 Subject: [PATCH 207/326] Fix a minor typo in the text styles example --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index c86d1074..f2bf7791 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -84,7 +84,7 @@ Inline style examples: $textrun = $section->addTextRun(); $textrun->addText('I am bold', array('bold' => true)); $textrun->addText('I am italic', array('italic' => true)); - $textrun->addText('I am colored, array('color' => 'AACC00')); + $textrun->addText('I am colored', array('color' => 'AACC00')); Defined style examples: From eb32ff2e151f516ad0d0a91019ca6565e9911c07 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 28 May 2014 08:50:09 +0200 Subject: [PATCH 208/326] #244 : Fix typo in recipe sample --- docs/recipes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.rst b/docs/recipes.rst index d900af8a..eef31527 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -13,7 +13,7 @@ vertically. $imageStyle = array( 'width' => 40, - 'height' => 40 + 'height' => 40, 'wrappingStyle' => 'square', 'positioning' => 'absolute', 'posHorizontalRel' => 'margin', From 87f071d1b63183ffaf8801840386c65b4b9978e5 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 27 May 2014 23:41:15 +0700 Subject: [PATCH 209/326] #72: Basic RTF Reader --- samples/Sample_27_ReadRTF.php | 17 ++ samples/resources/rtf.rtf | 21 ++ src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Reader/AbstractReader.php | 2 +- src/PhpWord/Reader/RTF.php | 50 ++++ src/PhpWord/Reader/RTF/Document.php | 351 +++++++++++++++++++++++++ src/PhpWord/Shared/XMLReader.php | 22 +- src/PhpWord/Writer/RTF/Part/Header.php | 2 +- 8 files changed, 459 insertions(+), 8 deletions(-) create mode 100644 samples/Sample_27_ReadRTF.php create mode 100644 samples/resources/rtf.rtf create mode 100644 src/PhpWord/Reader/RTF.php create mode 100644 src/PhpWord/Reader/RTF/Document.php diff --git a/samples/Sample_27_ReadRTF.php b/samples/Sample_27_ReadRTF.php new file mode 100644 index 00000000..a28ba40b --- /dev/null +++ b/samples/Sample_27_ReadRTF.php @@ -0,0 +1,17 @@ +canRead($docFile)) { + $doc = new Document(); + $doc->rtf = file_get_contents($docFile); + $doc->read($phpWord); + } else { + throw new \Exception("Cannot read {$docFile}."); + } + + return $phpWord; + } +} diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php new file mode 100644 index 00000000..ccb9b595 --- /dev/null +++ b/src/PhpWord/Reader/RTF/Document.php @@ -0,0 +1,351 @@ + 'markOpening', // { + 125 => 'markClosing', // } + 92 => 'markBackslash', // \ + 10 => 'markNewline', // LF + 13 => 'markNewline' // CR + ); + + $this->phpWord = $phpWord; + $this->section = $phpWord->addSection(); + $this->textrun = $this->section->addTextRun(); + $this->length = strlen($this->rtf); + + $this->flags['paragraph'] = true; // Set paragraph flag from the beginning + + // Walk each characters + while ($this->offset < $this->length) { + $char = $this->rtf[$this->offset]; + $ascii = ord($char); + + if (array_key_exists($ascii, $markers)) { // Marker found: {, }, \, LF, or CR + $markerFunction = $markers[$ascii]; + $this->$markerFunction(); + } else { + if ($this->isControl === false) { // Non control word: Push character + $this->pushText($char); + } else { + if (preg_match("/^[a-zA-Z0-9-]?$/", $char)) { // No delimiter: Buffer control + $this->control .= $char; + $this->isFirst = false; + } else { // Delimiter found: Parse buffered control + if ($this->isFirst) { + $this->isFirst = false; + } else { + if ($char == ' ') { // Discard space as a control word delimiter + $this->flushControl(true); + } + } + } + } + } + $this->offset++; + } + $this->flushText(); + } + + /** + * Mark opening braket `{` character + */ + private function markOpening() + { + $this->flush(true); + array_push($this->groups, $this->flags); + } + + /** + * Mark closing braket `}` character + */ + private function markClosing() + { + $this->flush(true); + $this->flags = array_pop($this->groups); + } + + /** + * Mark backslash `\` character + */ + private function markBackslash() + { + if ($this->isFirst) { + $this->setControl(false); + $this->text .= '\\'; + } else { + $this->flush(); + $this->setControl(true); + $this->control = ''; + } + } + + /** + * Mark newline character: Flush control word because it's not possible to span multiline + */ + private function markNewline() + { + if ($this->isControl) { + $this->flushControl(true); + } + } + + /** + * Flush control word or text + * + * @param bool $isControl + */ + private function flush($isControl = false) + { + if ($this->isControl) { + $this->flushControl($isControl); + } else { + $this->flushText(); + } + } + + /** + * Flush control word + * + * @param bool $isControl + */ + private function flushControl($isControl = false) + { + if (preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match) === 1) { + list(, $control, $parameter) = $match; + $this->parseControl($control, $parameter); + } + + if ($isControl === true) { + $this->setControl(false); + } + } + + /* + * Flush text in queue + */ + private function flushText() + { + if ($this->text != '') { + if (isset($this->flags['property'])) { + $this->flags['value'] = $this->text; + var_dump($this->flags); + } else { + if ($this->flags['paragraph'] === true) { + $this->flags['paragraph'] = false; + $this->flags['text'] = $this->text; + } + } + if (!isset($this->flags['skipped'])) { + $this->textrun->addText($this->text); + } + + $this->text = ''; + } + } + + /** + * Reset control word and first char state + * + * @param bool $state + */ + private function setControl($value) + { + $this->isControl = $value; + $this->isFirst = $value; + } + + /** + * Push text into queue + * + * @param string $char + */ + private function pushText($char) + { + if ($char == '<') { + $this->text .= "<"; + } elseif ($char == '>') { + $this->text .= ">"; + } else { + $this->text .= $char; + } + } + + /** + * Parse control + * + * @param string $control + * @param string $parameter + */ + private function parseControl($control, $parameter) + { + $controls = array( + 'par' => array(self::PARA, 'paragraph', true), + 'b' => array(self::STYL, 'bold', true), + 'i' => array(self::STYL, 'italic', true), + 'u' => array(self::STYL, 'underline', true), + 'fonttbl' => array(self::SKIP, 'fonttbl', null), + 'colortbl' => array(self::SKIP, 'colortbl', null), + 'info' => array(self::SKIP, 'info', null), + 'generator' => array(self::SKIP, 'generator', null), + 'title' => array(self::SKIP, 'title', null), + 'subject' => array(self::SKIP, 'subject', null), + 'category' => array(self::SKIP, 'category', null), + 'keywords' => array(self::SKIP, 'keywords', null), + 'comment' => array(self::SKIP, 'comment', null), + 'shppict' => array(self::SKIP, 'pic', null), + 'fldinst' => array(self::SKIP, 'link', null), + ); + + if (array_key_exists($control, $controls)) { + list($mode, $property, $value) = $controls[$control]; + switch ($mode) { + case self::PARA: // Paragraph + $this->textrun = $this->section->addTextRun(); + $this->flags[$property] = $value; + break; + case self::STYL: // Style + $this->flags[$property] = $value; + break; + case self::SKIP: // Destination + $this->flags['property'] = $property; + $this->flags['skipped'] = true; + } + } + } +} diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 60474ce9..153152ee 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -56,18 +56,30 @@ class XMLReader $zip = new ZipArchive(); $zip->open($zipFile); - $contents = $zip->getFromName($xmlFile); + $content = $zip->getFromName($xmlFile); $zip->close(); - if ($contents === false) { + if ($content === false) { return false; } else { - $this->dom = new \DOMDocument(); - $this->dom->loadXML($contents); - return $this->dom; + return $this->getDomFromString($content); } } + /** + * Get DOMDocument from content string + * + * @param string $content + * @return \DOMDocument + */ + public function getDomFromString($content) + { + $this->dom = new \DOMDocument(); + $this->dom->loadXML($content); + + return $this->dom; + } + /** * Get elements * diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index c401b500..15a0c303 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -123,7 +123,7 @@ class Header extends AbstractPart $content .= '{'; $content .= '\fonttbl'; foreach ($this->fontTable as $index => $font) { - $content .= "{\\f{$index}\\fnil\\fcharset0{$font};}"; + $content .= "{\\f{$index}\\fnil\\fcharset0 {$font};}"; } $content .= '}'; $content .= PHP_EOL; From 079d08e94a431341c4e8ebb5e092dca4493032dd Mon Sep 17 00:00:00 2001 From: Bas-Jan 't Jong Date: Wed, 28 May 2014 17:59:44 +0200 Subject: [PATCH 210/326] Added Field Element --- samples/Sample_27_Field.php | 21 +++++ src/PhpWord/Element/AbstractContainer.php | 12 +-- src/PhpWord/Element/Field.php | 75 ++++++++-------- src/PhpWord/Writer/Word2007/Element/Field.php | 88 +++++++++++++++++++ tests/PhpWord/Tests/Element/FieldTest.php | 75 ++++++++++++++++ 5 files changed, 225 insertions(+), 46 deletions(-) create mode 100644 samples/Sample_27_Field.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Field.php create mode 100644 tests/PhpWord/Tests/Element/FieldTest.php diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php new file mode 100644 index 00000000..6a556cca --- /dev/null +++ b/samples/Sample_27_Field.php @@ -0,0 +1,21 @@ +addSection(); + +// Add Field elements +// See Element/Field.php for all options +$section->addField('DATE', array('dateformat'=>'d-M-yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); +$section->addField('PAGE', array('format'=>'ArabicDash')); +$section->addField('NUMPAGES', array('format'=>'Arabic', 'numformat'=>'0,00'), array('PreserveFormat')); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 56425f4f..85aa5d5a 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -56,7 +56,7 @@ abstract class AbstractContainer extends AbstractElement // Get arguments $args = func_get_args(); - $withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun')); + $withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field')); if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { $args[3] = null; // Remove paragraph style for texts in textrun } @@ -147,14 +147,10 @@ abstract class AbstractContainer extends AbstractElement * Add field element * @param */ - public function addField($type = null, $properties = array(), $options = array()){ - //$this->checkValidity('Field'); - $elementDocPart = $this->checkElementDocPart(); - $element = new Field($type, $properties, $options); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); + public function addField($type = null, $properties = array(), $options = array()) + { + return $this->addElement('Field', $type, $properties, $options); - return $element; } /** diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 111d774e..5d6101e2 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -15,19 +15,6 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -/* - * - - - - - 5 - - - - */ - - namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Shared\String; @@ -37,22 +24,35 @@ use PhpOffice\PhpWord\Shared\String; */ class Field extends AbstractElement { - /** @const */ - //self::$fieldsArray; + + /** + * Field properties and options. Depending on type, a field can have different properties + * and options + * + * @var array + */ protected $fieldsArray = array( - 'PAGE'=>array( - 'properties'=>array( - 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), - ), - 'options'=>array() + 'PAGE'=>array( + 'properties'=>array( + 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), + ), + 'options'=>array('PreserveFormat') ), 'NUMPAGES'=>array( - 'properties'=>array( - 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), - 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%') - ), - 'options'=>array() + 'properties'=>array( + 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), + 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%') + ), + 'options'=>array('PreserveFormat') + ), + 'DATE'=>array( + 'properties'=> array( + 'dateformat' =>array('d-M-yyyy', 'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-M-yy', 'yyyy-MM-dd', + 'd-MMM-yy', 'd/M/yyyy', 'd MMM. yy', 'd/M/yy', 'MMM-yy', 'd-M-yyy H:mm', 'd-M-yyyy H:mm:ss', + 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss') + ), + 'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') ) ); @@ -128,15 +128,14 @@ class Field extends AbstractElement public function setProperties($properties = array()) { if (is_array($properties)) { -//CREATE FUNCTION, WHICH MATCHES SUBARRAY - - if (array_key_exists($properties, $this->fieldsArray[$this->type])) { - $this->properties=array_merge($this->properties, $properties); - } else { - throw new \InvalidArgumentException("Invalid property"); + foreach ($properties as $propkey => $propval) { + if (!(array_key_exists($propkey, $this->fieldsArray[$this->type]['properties']))) { + throw new \InvalidArgumentException("Invalid property"); + } } + $this->properties=array_merge($this->properties, $properties); } - return self; + return $this->properties; } /** @@ -158,13 +157,14 @@ class Field extends AbstractElement public function setOptions($options = array()) { if (is_array($options)) { - if (array_key_exists($options, self::$fieldsArray[$this->type])) { - $this->options=array_merge($this->options, $options); - } else { - throw new \InvalidArgumentException("Invalid option"); + foreach ($options as $optionkey => $optionval) { + if (!(array_key_exists($optionkey, $this->fieldsArray[$this->type]['options']))) { + throw new \InvalidArgumentException("Invalid option"); + } } + $this->options=array_merge($this->options, $options); } - return self; + return $this->options; } /** @@ -176,5 +176,4 @@ class Field extends AbstractElement { return $this->options; } - } diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php new file mode 100644 index 00000000..24656537 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -0,0 +1,88 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + return; + } + + $instruction=' '.$element->getType().' '; + $properties=$element->getProperties(); + foreach ($properties as $propkey => $propval) { + switch ($propkey) { + case 'format': + $instruction.='\* '.$propval.' '; + break; + case 'numformat': + $instruction.='\* '.$propval.' '; + break; + case 'dateformat': + $instruction.='\@ "'.$propval.'" '; + break; + } + } + + $options=$element->getOptions(); + foreach ($options as $option) { + switch ($option) { + case 'PreserveFormat': + $instruction.='\* MERGEFORMAT '; + break; + case 'LunarCalendar': + $instruction.='\h '; + break; + case 'SakaEraCalendar': + $instruction.='\s '; + break; + case 'LastUsedFormat': + $instruction.='\l '; + break; + } + } + $this->writeOpeningWP(); + $xmlWriter->startElement('w:fldSimple'); + $xmlWriter->writeAttribute('w:instr', $instruction); + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:noProof'); + $xmlWriter->endElement(); // w:noProof + $xmlWriter->endElement(); // w:rPr + + $xmlWriter->startElement('w:t'); + $xmlWriter->writeRaw('1'); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:fldSimple + + $this->writeClosingWP(); + } +} diff --git a/tests/PhpWord/Tests/Element/FieldTest.php b/tests/PhpWord/Tests/Element/FieldTest.php new file mode 100644 index 00000000..68fd8a84 --- /dev/null +++ b/tests/PhpWord/Tests/Element/FieldTest.php @@ -0,0 +1,75 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + } + + /** + * New instance with type + */ + public function testConstructWithType() + { + $oField = new Field('DATE'); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals($oField->getType(), 'DATE'); + } + + /** + * New instance with type and properties + */ + public function testConstructWithTypeProperties() + { + $oField = new Field('DATE', array('dateformat'=>'d-M-yyyy')); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals($oField->getType(), 'DATE'); + $this->assertEquals($oField->getProperties(), array('dateformat'=>'d-M-yyyy')); + } + + /** + * New instance with type and properties and options + */ + public function testConstructWithTypePropertiesOptions() + { + $oField = new Field('DATE', array('dateformat'=>'d-M-yyyy'), array('SakaEraCalendar', 'PreserveFormat')); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals($oField->getType(), 'DATE'); + $this->assertEquals($oField->getProperties(), array('dateformat'=>'d-M-yyyy')); + $this->assertEquals($oField->getOptions(), array('SakaEraCalendar', 'PreserveFormat')); + } +} From 8f74f26fd483d9ef8f56250388df37bf708d0072 Mon Sep 17 00:00:00 2001 From: Bas-Jan 't Jong Date: Wed, 28 May 2014 20:35:24 +0200 Subject: [PATCH 211/326] Travis build error fix --- src/PhpWord/Element/Field.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 5d6101e2..0bde0387 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -128,7 +128,7 @@ class Field extends AbstractElement public function setProperties($properties = array()) { if (is_array($properties)) { - foreach ($properties as $propkey => $propval) { + foreach (array_keys($properties) as $propkey) { if (!(array_key_exists($propkey, $this->fieldsArray[$this->type]['properties']))) { throw new \InvalidArgumentException("Invalid property"); } @@ -157,7 +157,7 @@ class Field extends AbstractElement public function setOptions($options = array()) { if (is_array($options)) { - foreach ($options as $optionkey => $optionval) { + foreach (array_keys($options) as $optionkey) { if (!(array_key_exists($optionkey, $this->fieldsArray[$this->type]['options']))) { throw new \InvalidArgumentException("Invalid option"); } From 2d88ea22b4f0bd3ea6f62a81ff3fc4b676f3e016 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 29 May 2014 15:09:02 +0700 Subject: [PATCH 212/326] RTF Reader: Split control parsers into functions --- samples/Sample_11_ReadWord2007.php | 3 +- samples/Sample_24_ReadODText.php | 3 +- samples/Sample_27_ReadRTF.php | 4 +- samples/Sample_Header.php | 4 +- .../{rtf.rtf => Sample_27_ReadRTF.rtf} | 0 src/PhpWord/Reader/RTF.php | 1 + src/PhpWord/Reader/RTF/Document.php | 82 +++++++++++++------ 7 files changed, 64 insertions(+), 33 deletions(-) rename samples/resources/{rtf.rtf => Sample_27_ReadRTF.rtf} (100%) diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index 09d9cab0..c0b54c7a 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -3,7 +3,8 @@ include_once 'Sample_Header.php'; // Read contents $name = basename(__FILE__, '.php'); -$source = "resources/{$name}.docx"; +$source = __DIR__ . "/resources/{$name}.docx"; + echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source); diff --git a/samples/Sample_24_ReadODText.php b/samples/Sample_24_ReadODText.php index bb5332e6..42df23ae 100644 --- a/samples/Sample_24_ReadODText.php +++ b/samples/Sample_24_ReadODText.php @@ -3,7 +3,8 @@ include_once 'Sample_Header.php'; // Read contents $name = basename(__FILE__, '.php'); -$source = "resources/{$name}.odt"; +$source = __DIR__ . "/resources/{$name}.odt"; + echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'ODText'); diff --git a/samples/Sample_27_ReadRTF.php b/samples/Sample_27_ReadRTF.php index a28ba40b..76ac3d48 100644 --- a/samples/Sample_27_ReadRTF.php +++ b/samples/Sample_27_ReadRTF.php @@ -3,9 +3,7 @@ include_once 'Sample_Header.php'; // Read contents $name = basename(__FILE__, '.php'); -$source = "results/Sample_01_SimpleText.rtf"; -$source = "resources/rtf.rtf"; -$source = "results/Sample_11_ReadWord2007.rtf"; +$source = __DIR__ . "/resources/{$name}.rtf"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'RTF'); diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index f39bda16..7af23c94 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -63,8 +63,8 @@ function write($phpWord, $filename, $writers) $result .= date('H:i:s') . " Write to {$writer} format"; if (!is_null($extension)) { $xmlWriter = IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$filename}.{$extension}"); - rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + $xmlWriter->save(__DIR__ . "/{$filename}.{$extension}"); + rename(__DIR__ . "/{$filename}.{$extension}", __DIR__ . "/results/{$filename}.{$extension}"); } else { $result .= ' ... NOT DONE!'; } diff --git a/samples/resources/rtf.rtf b/samples/resources/Sample_27_ReadRTF.rtf similarity index 100% rename from samples/resources/rtf.rtf rename to samples/resources/Sample_27_ReadRTF.rtf diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index 1856116c..9d5d813b 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -31,6 +31,7 @@ class RTF extends AbstractReader implements ReaderInterface * Loads PhpWord from file * * @param string $docFile + * @throws \Exception * @return \PhpOffice\PhpWord\PhpWord */ public function load($docFile) diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index ccb9b595..84e9c1ed 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -18,8 +18,6 @@ namespace PhpOffice\PhpWord\Reader\RTF; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Element\Section; -use PhpOffice\PhpWord\Element\TextRun; /** * RTF document reader @@ -35,9 +33,9 @@ use PhpOffice\PhpWord\Element\TextRun; class Document { /** @const int */ - const PARA = 0; - const STYL = 1; - const SKIP = 2; + const PARA = 'readParagraph'; + const STYL = 'readStyle'; + const SKIP = 'readSkip'; /** * PhpWord object @@ -247,8 +245,8 @@ class Document private function flushControl($isControl = false) { if (preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match) === 1) { - list(, $control, $parameter) = $match; - $this->parseControl($control, $parameter); + list(, $control) = $match; + $this->parseControl($control); } if ($isControl === true) { @@ -256,23 +254,25 @@ class Document } } - /* + /** * Flush text in queue */ private function flushText() { if ($this->text != '') { - if (isset($this->flags['property'])) { + if (isset($this->flags['property'])) { // Set property $this->flags['value'] = $this->text; - var_dump($this->flags); - } else { + } else { // Set text if ($this->flags['paragraph'] === true) { $this->flags['paragraph'] = false; $this->flags['text'] = $this->text; } } + + // Add text if it's not flagged as skipped if (!isset($this->flags['skipped'])) { - $this->textrun->addText($this->text); + $textrun = $this->textrun->addText($this->text); + $this->flags['element'] = &$textrun; } $this->text = ''; @@ -282,7 +282,7 @@ class Document /** * Reset control word and first char state * - * @param bool $state + * @param bool $value */ private function setControl($value) { @@ -312,7 +312,7 @@ class Document * @param string $control * @param string $parameter */ - private function parseControl($control, $parameter) + private function parseControl($control) { $controls = array( 'par' => array(self::PARA, 'paragraph', true), @@ -333,19 +333,49 @@ class Document ); if (array_key_exists($control, $controls)) { - list($mode, $property, $value) = $controls[$control]; - switch ($mode) { - case self::PARA: // Paragraph - $this->textrun = $this->section->addTextRun(); - $this->flags[$property] = $value; - break; - case self::STYL: // Style - $this->flags[$property] = $value; - break; - case self::SKIP: // Destination - $this->flags['property'] = $property; - $this->flags['skipped'] = true; + list($function) = $controls[$control]; + if (method_exists($this, $function)) { + $this->$function($controls[$control]); } } } + + /** + * Read paragraph + * + * @param array $directives + */ + private function readParagraph($directives) + { + list(, $property, $value) = $directives; + $this->textrun = $this->section->addTextRun(); + $this->flags[$property] = $value; + } + + /** + * Read style + * + * @param array $directives + */ + private function readStyle($directives) + { + list(, $property, $value) = $directives; + $this->flags[$property] = $value; + if (isset($this->flags['element'])) { + $element = &$this->flags['element']; + $element->getFontStyle()->setStyleValue($property, $value); + } + } + + /** + * Read skip + * + * @param array $directives + */ + private function readSkip($directives) + { + list(, $property) = $directives; + $this->flags['property'] = $property; + $this->flags['skipped'] = true; + } } From e81d92e26529ced07481f898661526c6ca7f4a9d Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 29 May 2014 16:21:15 +0700 Subject: [PATCH 213/326] Update changelog, docs, and unit tests for new `Field` element #251 --- CHANGELOG.md | 8 +-- docs/elements.rst | 18 +++++- docs/src/documentation.md | 16 +++++- samples/Sample_27_Field.php | 12 +++- src/PhpWord/Element/AbstractContainer.php | 10 +++- src/PhpWord/Element/Field.php | 55 +++++++++---------- src/PhpWord/Writer/Word2007/Element/Field.php | 29 +++++----- .../Tests/Writer/Word2007/ElementTest.php | 2 +- .../Writer/Word2007/Part/DocumentTest.php | 4 ++ 9 files changed, 98 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f0c3ee..4584c4a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,15 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.11.0 - Not yet released -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new relative and absolute positioning for image; new `TextBox` and `ListItemRun` element; refactorings of writer classes into parts, elements, and styles; and ability to add elements to PHPWord object via HTML. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. ### Features - Image: Ability to define relative and absolute positioning - @basjan GH-217 - Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin GH-219 -- TextBox: Ability to add textbox in section, header, and footer - @basjan @ivanlanin GH-228 GH-229 -- TextBox: Ability to add table inside textbox - @basjan GH-231 +- Element: New `TextBox` element - @basjan @ivanlanin GH-228 GH-229 GH-231 - HTML: Ability to add elements to PHPWord object via html - @basjan GH-231 -- ListItemRun: New element that can add a list item with inline formatting like a textrun - @basjan GH-235 +- Element: New `ListItemRun` element that can add a list item with inline formatting like a textrun - @basjan GH-235 - Table: Ability to add table inside a cell (nested table) - @ivanlanin GH-149 - RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin GH-158 - Table: Ability to define table width (in percent and twip) and position - @ivanlanin GH-237 @@ -30,6 +29,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r - Image: Enable "image float left" - @ivanlanin GH-244 - RTF Writer: Ability to write document properties - @ivanlanin - RTF Writer: Ability to write image - @ivanlanin +- Element: New `Field` element - @basjan GH-251 ### Bugfixes diff --git a/docs/elements.rst b/docs/elements.rst index c86d1074..7e0c33f6 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -17,7 +17,7 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 4 | Title | v | ? | ? | ? | ? | ? | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ -| 5 | Preserve Text | ? | v | v | v\* | ? | ? | +| 5 | Preserve Text | ? | v | v | v\* | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 6 | Text Break | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ @@ -39,7 +39,11 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 15 | Endnote | v | - | - | v\*\* | v\*\* | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ -| 16 | CheckBox | v | v | v | v | ? | ? | +| 16 | CheckBox | v | v | v | v | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 17 | TextBox | v | v | v | v | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 18 | Field | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -473,3 +477,13 @@ Checkbox elements can be added to sections or table cells by using - ``$text`` Text following the check box - ``$fontStyle`` See "Font style" section. - ``$paragraphStyle`` See "Paragraph style" section. + +Textboxes +--------- + +To be completed + +Fields +------ + +To be completed diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 6d34ff9f..889842f9 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -33,6 +33,8 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [Table of contents](#table-of-contents) - [Footnotes & endnotes](#footnotes-endnotes) - [Checkboxes](#checkboxes) + - [Textboxes](#textboxes) + - [Fields](#fields) - [Templates](#templates) - [Writers & readers](#writers-readers) - [OOXML](#ooxml) @@ -447,7 +449,7 @@ Below are the matrix of element availability in each container. The column shows | 2 | Text Run | v | v | v | v | - | - | | 3 | Link | v | v | v | v | v | v | | 4 | Title | v | ? | ? | ? | ? | ? | -| 5 | Preserve Text | ? | v | v | v* | ? | ? | +| 5 | Preserve Text | ? | v | v | v* | - | - | | 6 | Text Break | v | v | v | v | v | v | | 7 | Page Break | v | - | - | - | - | - | | 8 | List | v | v | v | v | - | - | @@ -458,7 +460,9 @@ Below are the matrix of element availability in each container. The column shows | 13 | TOC | v | - | - | - | - | - | | 14 | Footnote | v | - | - | v** | v** | - | | 15 | Endnote | v | - | - | v** | v** | - | -| 16 | CheckBox | v | v | v | v | ? | ? | +| 16 | CheckBox | v | v | v | v | - | - | +| 17 | TextBox | v | v | v | v | - | - | +| 18 | Field | v | v | v | v | v | v | Legend: @@ -832,6 +836,14 @@ $section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]) - `$fontStyle` See "Font style" section. - `$paragraphStyle` See "Paragraph style" section. +## Textboxes + +To be completed. + +## Fields + +To be completed. + # Templates You can create a docx template with included search-patterns that can be replaced by any value you wish. Only single-line values can be replaced. To load a template file, use the `loadTemplate` method. After loading the docx template, you can use the `setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. It is not possible to add new PHPWord elements to a loaded template file. diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 6a556cca..fd750372 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -10,10 +10,20 @@ $section = $phpWord->addSection(); // Add Field elements // See Element/Field.php for all options -$section->addField('DATE', array('dateformat'=>'d-M-yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); +$section->addText('Date field:'); +$section->addField('DATE', array('dateformat'=>'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); + +$section->addText('Page field:'); $section->addField('PAGE', array('format'=>'ArabicDash')); + +$section->addText('Number of pages field:'); $section->addField('NUMPAGES', array('format'=>'Arabic', 'numformat'=>'0,00'), array('PreserveFormat')); +$textrun = $section->addTextRun(array('align' => 'center')); +$textrun->addText('This is the date of lunar calendar '); +$textrun->addField('DATE', array('dateformat'=>'d-M-yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); +$textrun->addText(' written in a textrun.'); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 85aa5d5a..71c5ae2a 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -145,14 +145,17 @@ abstract class AbstractContainer extends AbstractElement /** * Add field element - * @param + * + * @param string $type + * @param array $properties + * @param array $options */ public function addField($type = null, $properties = array(), $options = array()) { return $this->addElement('Field', $type, $properties, $options); - + } - + /** * Add link element * @@ -327,6 +330,7 @@ abstract class AbstractContainer extends AbstractElement 'TextBreak' => $allContainers, 'Image' => $allContainers, 'Object' => $allContainers, + 'Field' => $allContainers, 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 0bde0387..7503dc9b 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -1,35 +1,34 @@ array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') ) ); - + /** * Field type * @@ -81,8 +80,8 @@ class Field extends AbstractElement * Create a new Field Element * * @param string $type - * @param mixed $properties - * @param mixed $options + * @param array $properties + * @param array $options */ public function __construct($type = null, $properties = array(), $options = array()) { @@ -94,7 +93,7 @@ class Field extends AbstractElement /** * Set Field type * - * @param string + * @param string $type * @return string */ public function setType($type = null) @@ -122,7 +121,7 @@ class Field extends AbstractElement /** * Set Field properties * - * @param array + * @param array $properties * @return self */ public function setProperties($properties = array()) @@ -130,10 +129,10 @@ class Field extends AbstractElement if (is_array($properties)) { foreach (array_keys($properties) as $propkey) { if (!(array_key_exists($propkey, $this->fieldsArray[$this->type]['properties']))) { - throw new \InvalidArgumentException("Invalid property"); + throw new \InvalidArgumentException("Invalid property"); } } - $this->properties=array_merge($this->properties, $properties); + $this->properties = array_merge($this->properties, $properties); } return $this->properties; } @@ -151,7 +150,7 @@ class Field extends AbstractElement /** * Set Field options * - * @param array + * @param array $options * @return self */ public function setOptions($options = array()) @@ -162,11 +161,11 @@ class Field extends AbstractElement throw new \InvalidArgumentException("Invalid option"); } } - $this->options=array_merge($this->options, $options); + $this->options = array_merge($this->options, $options); } return $this->options; } - + /** * Get Field properties * diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 24656537..68c4c40c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -20,7 +20,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** * Field element writer * - * @since 0.10.0 + * @since 0.11.0 */ class Field extends Text { @@ -30,44 +30,43 @@ class Field extends Text public function write() { $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); + $element = $this->getElement(); if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { return; } - $instruction=' '.$element->getType().' '; - $properties=$element->getProperties(); + $instruction = ' ' . $element->getType() . ' '; + $properties = $element->getProperties(); foreach ($properties as $propkey => $propval) { switch ($propkey) { case 'format': - $instruction.='\* '.$propval.' '; - break; case 'numformat': - $instruction.='\* '.$propval.' '; + $instruction .= '\* ' . $propval . ' '; break; case 'dateformat': - $instruction.='\@ "'.$propval.'" '; + $instruction .= '\@ "' . $propval . '" '; break; } } - - $options=$element->getOptions(); + + $options = $element->getOptions(); foreach ($options as $option) { switch ($option) { case 'PreserveFormat': - $instruction.='\* MERGEFORMAT '; + $instruction .= '\* MERGEFORMAT '; break; case 'LunarCalendar': - $instruction.='\h '; + $instruction .= '\h '; break; case 'SakaEraCalendar': - $instruction.='\s '; + $instruction .= '\s '; break; case 'LastUsedFormat': - $instruction.='\l '; + $instruction .= '\l '; break; } } + $this->writeOpeningWP(); $xmlWriter->startElement('w:fldSimple'); $xmlWriter->writeAttribute('w:instr', $instruction); @@ -76,7 +75,7 @@ class Field extends Text $xmlWriter->startElement('w:noProof'); $xmlWriter->endElement(); // w:noProof $xmlWriter->endElement(); // w:rPr - + $xmlWriter->startElement('w:t'); $xmlWriter->writeRaw('1'); $xmlWriter->endElement(); // w:t diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 4d1d7ce2..ee8b88ae 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -30,7 +30,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase { $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', - 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC' + 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', 'Field' ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 8ed1246f..09f7d6a4 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -83,6 +83,10 @@ class DocumentTest extends \PHPUnit_Framework_TestCase 'innerMargin' => 10, 'borderSize' => 1, 'borderColor' => '#FF0')); $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'align' => 'center')); $section->addListItemRun()->addText('List item run 1'); + $section->addField('DATE', array('dateformat'=>'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); + $section->addField('DATE', array('dateformat'=>'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat', 'SakaEraCalendar')); + $section->addField('DATE', array('dateformat'=>'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat', 'LastUsedFormat')); + $section->addField('PAGE', array('format'=>'ArabicDash')); $doc = TestHelperDOCX::getDocument($phpWord); From 7a42802b4882cfe9ecda44b2b0131bb11059c641 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 29 May 2014 17:37:26 +0700 Subject: [PATCH 214/326] RTF reader: Unit tests and some improvements --- CHANGELOG.md | 3 +- docs/intro.rst | 2 +- docs/src/documentation.md | 2 +- ...e_27_ReadRTF.php => Sample_28_ReadRTF.php} | 0 ...e_27_ReadRTF.rtf => Sample_28_ReadRTF.rtf} | 0 src/PhpWord/Reader/RTF/Document.php | 70 +++++++++++-------- tests/PhpWord/Tests/Reader/ODTextTest.php | 4 +- tests/PhpWord/Tests/Reader/RTFTest.php | 51 ++++++++++++++ tests/PhpWord/Tests/Reader/Word2007Test.php | 33 ++------- .../PhpWord/Tests/_files/documents/reader.rtf | 21 ++++++ 10 files changed, 126 insertions(+), 60 deletions(-) rename samples/{Sample_27_ReadRTF.php => Sample_28_ReadRTF.php} (100%) rename samples/resources/{Sample_27_ReadRTF.rtf => Sample_28_ReadRTF.rtf} (100%) create mode 100644 tests/PhpWord/Tests/Reader/RTFTest.php create mode 100644 tests/PhpWord/Tests/_files/documents/reader.rtf diff --git a/CHANGELOG.md b/CHANGELOG.md index 4584c4a4..0ccba8cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.11.0 - Not yet released -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. ### Features @@ -30,6 +30,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three - RTF Writer: Ability to write document properties - @ivanlanin - RTF Writer: Ability to write image - @ivanlanin - Element: New `Field` element - @basjan GH-251 +- RTF Reader: Basic RTF reader - @ivanlanin GH-72 ### Bugfixes diff --git a/docs/intro.rst b/docs/intro.rst index a64fb2ad..3da729e8 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -124,7 +124,7 @@ Readers +---------------------------+----------------------+--------+-------+-------+ | | Custom | ✓ | | | +---------------------------+----------------------+--------+-------+-------+ -| **Element Type** | Text | ✓ | ✓ | | +| **Element Type** | Text | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+ | | Text Run | ✓ | | | +---------------------------+----------------------+--------+-------+-------+ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 889842f9..0f4d085b 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -114,7 +114,7 @@ Below are the supported features for each file formats. |-------------------------|--------------------|------|-----|-----| | **Document Properties** | Standard | ✓ | | | | | Custom | ✓ | | | -| **Element Type** | Text | ✓ | ✓ | | +| **Element Type** | Text | ✓ | ✓ | ✓ | | | Text Run | ✓ | | | | | Title | ✓ | ✓ | | | | Link | ✓ | | | diff --git a/samples/Sample_27_ReadRTF.php b/samples/Sample_28_ReadRTF.php similarity index 100% rename from samples/Sample_27_ReadRTF.php rename to samples/Sample_28_ReadRTF.php diff --git a/samples/resources/Sample_27_ReadRTF.rtf b/samples/resources/Sample_28_ReadRTF.rtf similarity index 100% rename from samples/resources/Sample_27_ReadRTF.rtf rename to samples/resources/Sample_28_ReadRTF.rtf diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 84e9c1ed..cb082fdc 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -245,8 +245,8 @@ class Document private function flushControl($isControl = false) { if (preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match) === 1) { - list(, $control) = $match; - $this->parseControl($control); + list(, $control, $parameter) = $match; + $this->parseControl($control, $parameter); } if ($isControl === true) { @@ -271,8 +271,7 @@ class Document // Add text if it's not flagged as skipped if (!isset($this->flags['skipped'])) { - $textrun = $this->textrun->addText($this->text); - $this->flags['element'] = &$textrun; + $this->readText(); } $this->text = ''; @@ -312,30 +311,36 @@ class Document * @param string $control * @param string $parameter */ - private function parseControl($control) + private function parseControl($control, $parameter) { $controls = array( - 'par' => array(self::PARA, 'paragraph', true), - 'b' => array(self::STYL, 'bold', true), - 'i' => array(self::STYL, 'italic', true), - 'u' => array(self::STYL, 'underline', true), - 'fonttbl' => array(self::SKIP, 'fonttbl', null), - 'colortbl' => array(self::SKIP, 'colortbl', null), - 'info' => array(self::SKIP, 'info', null), - 'generator' => array(self::SKIP, 'generator', null), - 'title' => array(self::SKIP, 'title', null), - 'subject' => array(self::SKIP, 'subject', null), - 'category' => array(self::SKIP, 'category', null), - 'keywords' => array(self::SKIP, 'keywords', null), - 'comment' => array(self::SKIP, 'comment', null), - 'shppict' => array(self::SKIP, 'pic', null), - 'fldinst' => array(self::SKIP, 'link', null), + 'par' => array(self::PARA, 'paragraph', true), + 'b' => array(self::STYL, 'font', 'bold', true), + 'i' => array(self::STYL, 'font', 'italic', true), + 'u' => array(self::STYL, 'font', 'underline', true), + 'strike' => array(self::STYL, 'font', 'strikethrough',true), + 'fs' => array(self::STYL, 'font', 'size', $parameter), + 'qc' => array(self::STYL, 'paragraph', 'align', 'center'), + 'sa' => array(self::STYL, 'paragraph', 'spaceAfter', $parameter), + 'fonttbl' => array(self::SKIP, 'fonttbl', null), + 'colortbl' => array(self::SKIP, 'colortbl', null), + 'info' => array(self::SKIP, 'info', null), + 'generator' => array(self::SKIP, 'generator', null), + 'title' => array(self::SKIP, 'title', null), + 'subject' => array(self::SKIP, 'subject', null), + 'category' => array(self::SKIP, 'category', null), + 'keywords' => array(self::SKIP, 'keywords', null), + 'comment' => array(self::SKIP, 'comment', null), + 'shppict' => array(self::SKIP, 'pic', null), + 'fldinst' => array(self::SKIP, 'link', null), ); if (array_key_exists($control, $controls)) { list($function) = $controls[$control]; if (method_exists($this, $function)) { - $this->$function($controls[$control]); + $directives = $controls[$control]; + array_shift($directives); // remove the function variable; we won't need it + $this->$function($directives); } } } @@ -347,7 +352,7 @@ class Document */ private function readParagraph($directives) { - list(, $property, $value) = $directives; + list($property, $value) = $directives; $this->textrun = $this->section->addTextRun(); $this->flags[$property] = $value; } @@ -359,12 +364,8 @@ class Document */ private function readStyle($directives) { - list(, $property, $value) = $directives; - $this->flags[$property] = $value; - if (isset($this->flags['element'])) { - $element = &$this->flags['element']; - $element->getFontStyle()->setStyleValue($property, $value); - } + list($style, $property, $value) = $directives; + $this->flags['styles'][$style][$property] = $value; } /** @@ -374,8 +375,19 @@ class Document */ private function readSkip($directives) { - list(, $property) = $directives; + list($property) = $directives; $this->flags['property'] = $property; $this->flags['skipped'] = true; } + + /** + * Read text + */ + private function readText() + { + $text = $this->textrun->addText($this->text); + if (isset($this->flags['styles']['font'])) { + $text->getFontStyle()->setStyleByArray($this->flags['styles']['font']); + } + } } diff --git a/tests/PhpWord/Tests/Reader/ODTextTest.php b/tests/PhpWord/Tests/Reader/ODTextTest.php index 4120c11e..fc4d2e33 100644 --- a/tests/PhpWord/Tests/Reader/ODTextTest.php +++ b/tests/PhpWord/Tests/Reader/ODTextTest.php @@ -33,7 +33,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase public function testLoad() { $filename = __DIR__ . '/../_files/documents/reader.odt'; - $object = IOFactory::load($filename, 'ODText'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object); + $phpWord = IOFactory::load($filename, 'ODText'); + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); } } diff --git a/tests/PhpWord/Tests/Reader/RTFTest.php b/tests/PhpWord/Tests/Reader/RTFTest.php new file mode 100644 index 00000000..c495db68 --- /dev/null +++ b/tests/PhpWord/Tests/Reader/RTFTest.php @@ -0,0 +1,51 @@ +assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + } + + /** + * Test load exception + * + * @expectedException \Exception + * @expectedExceptionMessage Cannot read + */ + public function testLoadException() + { + $filename = __DIR__ . '/../_files/documents/foo.rtf'; + IOFactory::load($filename, 'RTF'); + } +} diff --git a/tests/PhpWord/Tests/Reader/Word2007Test.php b/tests/PhpWord/Tests/Reader/Word2007Test.php index 58890c9a..f2257012 100644 --- a/tests/PhpWord/Tests/Reader/Word2007Test.php +++ b/tests/PhpWord/Tests/Reader/Word2007Test.php @@ -28,40 +28,24 @@ use PhpOffice\PhpWord\Reader\Word2007; */ class Word2007Test extends \PHPUnit_Framework_TestCase { - /** - * Init - */ - public function tearDown() - { - } - /** * Test canRead() method */ public function testCanRead() { $object = new Word2007(); - $fqFilename = join( - DIRECTORY_SEPARATOR, - array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'documents', 'reader.docx') - ); - $this->assertTrue($object->canRead($fqFilename)); + $filename = __DIR__ . '/../_files/documents/reader.docx'; + $this->assertTrue($object->canRead($filename)); } /** * Can read exception - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testCanReadFailed() { $object = new Word2007(); - $fqFilename = join( - DIRECTORY_SEPARATOR, - array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'documents', 'foo.docx') - ); - $this->assertFalse($object->canRead($fqFilename)); - $object = IOFactory::load($fqFilename); + $filename = __DIR__ . '/../_files/documents/foo.docx'; + $this->assertFalse($object->canRead($filename)); } /** @@ -69,11 +53,8 @@ class Word2007Test extends \PHPUnit_Framework_TestCase */ public function testLoad() { - $fqFilename = join( - DIRECTORY_SEPARATOR, - array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'documents', 'reader.docx') - ); - $object = IOFactory::load($fqFilename); - $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object); + $filename = __DIR__ . '/../_files/documents/reader.docx'; + $phpWord = IOFactory::load($filename); + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); } } diff --git a/tests/PhpWord/Tests/_files/documents/reader.rtf b/tests/PhpWord/Tests/_files/documents/reader.rtf new file mode 100644 index 00000000..400f43a5 --- /dev/null +++ b/tests/PhpWord/Tests/_files/documents/reader.rtf @@ -0,0 +1,21 @@ +{\rtf1 +\ansi\ansicpg1252 +\deff0 +{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fnil\fcharset0 Times New Roman;}} +{\colortbl;\red255\green0\blue0;\red14\green0\blue0} +{\*\generator PhpWord;} + +{\info{\title }{\subject }{\category }{\keywords }{\comment }{\author }{\operator }{\creatim \yr2014\mo05\dy27\hr23\min36\sec45}{\revtim \yr2014\mo05\dy27\hr23\min36\sec45}{\company }{\manager }} +\deftab720\viewkind1\uc1\pard\nowidctlpar\lang1036\kerning1\fs20 +{Welcome to PhpWord}\par +\pard\nowidctlpar{\cf0\f0 Hello World!}\par +\par +\par +\pard\nowidctlpar{\cf0\f0\fs32\b\i I am styled by a definition.}\par +\pard\nowidctlpar{\cf0\f0 I am styled by a paragraph style definition.}\par +\pard\nowidctlpar\qc\sa100{\cf0\f0\fs32\b\i I am styled by both font and paragraph style.}\par +\pard\nowidctlpar{\cf1\f1\fs40\b\i\ul\strike\super I am inline styled.}\par +\par +{\field {\*\fldinst {HYPERLINK "http://www.google.com"}}{\fldrslt {Google}}}\par +\par +} \ No newline at end of file From 4bb3ffe5bd6cf6752d630393011bb4a381d26520 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 29 May 2014 18:13:57 +0700 Subject: [PATCH 215/326] Apply #250 fix a minor typo in the text styles example --- docs/elements.rst | 2 +- docs/src/documentation.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 7e0c33f6..901832eb 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -88,7 +88,7 @@ Inline style examples: $textrun = $section->addTextRun(); $textrun->addText('I am bold', array('bold' => true)); $textrun->addText('I am italic', array('italic' => true)); - $textrun->addText('I am colored, array('color' => 'AACC00')); + $textrun->addText('I am colored', array('color' => 'AACC00')); Defined style examples: diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 0f4d085b..0259dd8b 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -495,7 +495,7 @@ $section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); $textrun = $section->addTextRun(); $textrun->addText('I am bold', array('bold' => true)); $textrun->addText('I am italic', array('italic' => true)); -$textrun->addText('I am colored, array('color' => 'AACC00')); +$textrun->addText('I am colored', array('color' => 'AACC00')); ``` Defined style examples: From 1580113d7b885c6717f21cf8c6190eb3841e0a3a Mon Sep 17 00:00:00 2001 From: Bas-Jan 't Jong Date: Thu, 29 May 2014 16:44:00 +0200 Subject: [PATCH 216/326] Added Line element --- CHANGELOG.md | 3 +- CHANGELOG.md~ | 268 +++++++++++++++++++ samples/Sample_28_Line.php | 64 +++++ src/PhpWord/Element/AbstractContainer.php | 14 + src/PhpWord/Element/Line.php | 54 ++++ src/PhpWord/Style/Line.php | 256 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/Line.php | 84 ++++++ src/PhpWord/Writer/Word2007/Style/Line.php | 180 +++++++++++++ tests/PhpWord/Tests/Element/LineTest.php | 76 ++++++ tests/PhpWord/Tests/Style/LineTest.php | 153 +++++++++++ 10 files changed, 1151 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md~ create mode 100644 samples/Sample_28_Line.php create mode 100644 src/PhpWord/Element/Line.php create mode 100644 src/PhpWord/Style/Line.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Line.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Line.php create mode 100644 tests/PhpWord/Tests/Element/LineTest.php create mode 100644 tests/PhpWord/Tests/Style/LineTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ccba8cc..a322b2e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.11.0 - Not yet released -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, Line and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. ### Features @@ -30,6 +30,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three - RTF Writer: Ability to write document properties - @ivanlanin - RTF Writer: Ability to write image - @ivanlanin - Element: New `Field` element - @basjan GH-251 +- Element: New `Line` element - @basjan - RTF Reader: Basic RTF reader - @ivanlanin GH-72 ### Bugfixes diff --git a/CHANGELOG.md~ b/CHANGELOG.md~ new file mode 100644 index 00000000..0ccba8cc --- /dev/null +++ b/CHANGELOG.md~ @@ -0,0 +1,268 @@ +# Changelog + +This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. + +## 0.11.0 - Not yet released + +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. + +### Features + +- Image: Ability to define relative and absolute positioning - @basjan GH-217 +- Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin GH-219 +- Element: New `TextBox` element - @basjan @ivanlanin GH-228 GH-229 GH-231 +- HTML: Ability to add elements to PHPWord object via html - @basjan GH-231 +- Element: New `ListItemRun` element that can add a list item with inline formatting like a textrun - @basjan GH-235 +- Table: Ability to add table inside a cell (nested table) - @ivanlanin GH-149 +- RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin GH-158 +- Table: Ability to define table width (in percent and twip) and position - @ivanlanin GH-237 +- RTF Writer: Ability to add links and page breaks in RTF - @ivanlanin GH-196 +- ListItemRun: Remove fontStyle parameter because ListItemRun is inherited from TextRun and TextRun doesn't have fontStyle - @ivanlanin +- Config: Ability to use a config file to store various common settings - @ivanlanin GH-200 +- ODT Writer: Enable inline font style in TextRun - @ivanlanin +- ODT Writer: Enable underline, strike/doublestrike, smallcaps/allcaps, superscript/subscript font style - @ivanlanin +- ODT Writer: Enable section and column - @ivanlanin +- PDF Writer: Add TCPDF and mPDF as optional PDF renderer library - @ivanlanin +- ODT Writer: Enable title element and custom document properties - @ivanlanin +- ODT Reader: Ability to read standard and custom document properties - @ivanlanin +- Word2007 Writer: Enable the missing custom document properties writer - @ivanlanin +- Image: Enable "image float left" - @ivanlanin GH-244 +- RTF Writer: Ability to write document properties - @ivanlanin +- RTF Writer: Ability to write image - @ivanlanin +- Element: New `Field` element - @basjan GH-251 +- RTF Reader: Basic RTF reader - @ivanlanin GH-72 + +### Bugfixes + +- Header: All images added to the second header were assigned to the first header - @basjan GH-222 +- Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan GH-233 GH-234 +- PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin GH-150 +- Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin GH-248 + +### Deprecated + +- Static classes `Footnotes`, `Endnotes`, and `TOC` +- `Writer\Word2007\Part`: `Numbering::writeNumbering()`, `Settings::writeSettings()`, `WebSettings::writeWebSettings()`, `ContentTypes::writeContentTypes()`, `Styles::writeStyles()`, `Document::writeDocument()` all changed into `write()` +- `Writer\Word2007\Part\DocProps`: Split into `Writer\Word2007\Part\DocPropsCore` and `Writer\Word2007\Part\DocPropsApp` +- `Element\Title::getBookmarkId()` replaced by `Element\Title::getRelationId()` +- `Writer\HTML::writeDocument`: Replaced by `Writer\HTML::getContent` + +### Miscellaneous + +- License: Change the project license from LGPL 2.1 into LGPL 3.0 - GH-211 +- Word2007 Writer: New `Style\Image` class - @ivanlanin +- Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin GH-206 +- QA: Reactivate `phpcpd` and `phpmd` on Travis - @ivanlanin +- Refactor: PHPMD recommendation: Change all `get...` method that returns `boolean` into `is...` or `has...` - @ivanlanin +- Docs: Create gh-pages branch for API documentation - @Progi1984 GH-154 +- QA: Add `.scrutinizer.yml` and include `composer.lock` for preparation to Scrutinizer - @ivanlanin GH-186 +- Writer: Refactor writer parts using composite pattern - @ivanlanin +- Docs: Show code quality and test code coverage badge on README +- Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin +- Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin + +## 0.10.1 - 21 May 2014 + +This is a bugfix release for `php-zip` requirement in Composer. + +- Change Composer requirements for php-zip from `require` to `suggest` - @bskrtich GH-246 + +## 0.10.0 - 4 May 2014 + +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled. Basic ODText reader is introduced. + +### Features + +- Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184 +- Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 GH-183 +- Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin +- Footnote: Ability to style footnote reference mark by using `FootnoteReference` style - @ivanlanin +- Font: Add `bgColor` to font style to define background using HEX color - @jcarignan GH-168 +- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168 +- Element: New `CheckBox` element for sections and table cells - @ozilion GH-156 +- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 +- Template: Ability to find & replace variables in headers & footers - @dgudgeon GH-190 +- Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira GH-191 +- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb GH-189 +- Table: Ability to add footnote in table cell - @ivanlanin GH-187 +- Footnote: Ability to add image in footnote - @ivanlanin GH-187 +- ListItem: Ability to add list item in header/footer - @ivanlanin GH-187 +- CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 +- Link: Ability to add link in header/footer - @ivanlanin GH-187 +- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 +- Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 +- General: Add `Style::resetStyles()` - @ivanlanin GH-187 +- DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image, and title - @ivanlanin +- Endnote: Ability to add endnotes - @ivanlanin +- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 +- ODT Writer: Basic table writing support - @ivanlanin +- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 +- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin GH-203 GH-67 GH-147 +- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68 +- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin +- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin +- ODT Writer: Basic image writing - @ivanlanin +- ODT Writer: Link writing - @ivanlanin +- ODT Reader: Basic ODText Reader - @ivanlanin GH-71 +- Section: Ability to define gutter and line numbering - @ivanlanin +- Font: Small caps, all caps, and double strikethrough - @ivanlanin GH-151 +- Settings: Ability to use measurement unit other than twips with `setMeasurementUnit` - @ivanlanin GH-199 +- Style: Remove `bgColor` from `Font`, `Table`, and `Cell` and put it into the new `Shading` style - @ivanlanin +- Style: New `Indentation` and `Spacing` style - @ivanlanin +- Paragraph: Ability to define first line and right indentation - @ivanlanin + +### Bugfixes + +- Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170 +- Documentation: Error in a function - @theBeerNut GH-195 + +### Deprecated + +- `createTextRun` replaced by `addTextRun` +- `createFootnote` replaced by `addFootnote` +- `createHeader` replaced by `addHeader` +- `createFooter` replaced by `addFooter` +- `createSection` replaced by `addSection` +- `Element\Footnote::getReferenceId` replaced by `Element\AbstractElement::getRelationId` +- `Element\Footnote::setReferenceId` replaced by `Element\AbstractElement::setRelationId` +- `Footnote::addFootnoteLinkElement` replaced by `Media::addElement` +- `Footnote::getFootnoteLinkElements` replaced by `Media::getElements` +- All current methods on `Media` +- `Element\Link::getLinkSrc` replaced by `Element\Link::getTarget` +- `Element\Link::getLinkName` replaced by `Element\Link::getText` +- `Style\Cell::getDefaultBorderColor` + +### Miscellaneous + +- Documentation: Simplify page level docblock - @ivanlanin GH-179 +- Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin GH-160 +- General: Refactor folders: `Element` and `Exception` - @ivanlanin GH-187 +- General: Remove legacy `HashTable` and `Shared\ZipStreamWrapper` and all related properties/methods - @ivanlanin GH-187 +- Element: New `AbstractElement` abstract class - @ivanlanin GH-187 +- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 +- General: Remove underscore prefix from all private properties name - @ivanlanin GH-187 +- General: Move Section `Settings` to `Style\Section` - @ivanlanin GH-187 +- General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin GH-187 +- Style: New `Style\AbstractStyle` abstract class - @ivanlanin GH-187 +- Writer: New 'ODText\Base` class - @ivanlanin GH-187 +- General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin +- General: Add some unit tests for Shared & Element (100%!) - @Progi1984 +- Test: Add some samples and tests for image wrapping style - @brunocasado GH-59 +- Refactor: Remove Style\Tabs - @ivanlanin +- Refactor: Apply composite pattern for writers - @ivanlanin +- Refactor: Split `AbstractContainer` from `AbstractElement` - @ivanlanin +- Refactor: Apply composite pattern for Word2007 reader - @ivanlanin + +## 0.9.1 - 27 Mar 2014 + +This is a bugfix release for PSR-4 compatibility. + +- Fixed PSR-4 composer autoloader - @AntonTyutin + +## 0.9.0 - 26 Mar 2014 + +This release marked the transformation to namespaces (PHP 5.3+). + +### Features + +- Image: Ability to use remote or GD images using `addImage()` on sections, headers, footer, cells, and textruns - @ivanlanin +- Header: Ability to use remote or GD images using `addWatermark()` - @ivanlanin + +### Bugfixes + +- Preserve text doesn't render correctly when the text is not the first word, e.g. 'Page {PAGE}' - @ivanlanin + +### Miscellaneous + +- Move documentation to [Read The Docs](http://phpword.readthedocs.org/en/develop/) - @Progi1984 @ivanlanin GH-82 +- Reorganize and redesign samples folder - @ivanlanin GH-137 +- Use `PhpOffice\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull GH-159 GH-58 +- Restructure folders and change folder name `Classes` to `src` and `Tests` to `test` for PSR compliance - @RomanSyroeshko @gabrielbull +- Compliance to phpDocumentor - @ivanlanin +- Merge Style\TableFull into Style\Table. Style\TableFull is deprecated - @ivanlanin GH-160 +- Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin GH-160 + +## 0.8.1 - 17 Mar 2014 + +This is a bugfix release for image detection functionality. + +- Added fallback for computers that do not have exif_imagetype - @bskrtich, @gabrielbull + +## 0.8.0 - 15 Mar 2014 + +This release merged a lot of improvements from the community. Unit tests introduced in this release and has reached 90% code coverage. + +### Features + +- Template: Permit to save a template generated as a file (PHPWord_Template::saveAs()) - @RomanSyroeshko GH-56 GH-57 +- Word2007: Support sections page numbering - @gabrielbull +- Word2007: Added line height methods to mirror the line height settings in Word in the paragraph styling - @gabrielbull +- Word2007: Added support for page header & page footer height - @JillElaine GH-5 +- General: Add ability to manage line breaks after image insertion - @bskrtich GH-6 GH-66 GH-84 +- Template: Ability to limit number of replacements performed by setValue() method of Template class - @RomanSyroeshko GH-52 GH-53 GH-85 +- Table row: Repeat as header row & allow row to break across pages - @ivanlanin GH-48 GH-86 +- Table: Table width in percentage - @ivanlanin GH-48 GH-86 +- Font: Superscript and subscript - @ivanlanin GH-48 GH-86 +- Paragraph: Hanging paragraph - @ivanlanin GH-48 GH-86 +- Section: Multicolumn and section break - @ivanlanin GH-48 GH-86 +- Template: Ability to apply XSL style sheet to Template - @RomanSyroeshko GH-46 GH-47 GH-83 +- General: PHPWord_Shared_Font::pointSizeToTwips() converter - @ivanlanin GH-87 +- Paragraph: Ability to define normal paragraph style with PHPWord::setNormalStyle() - @ivanlanin GH-87 +- Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next) - @ivanlanin GH-87 +- Clone table rows on the fly when using a template document - @jeroenmoors GH-44 GH-88 +- Initial addition of basic footnote support - @deds GH-16 +- Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before - @ivanlanin GH-92 +- General: PHPWord_Style_Font refactoring - @ivanlanin GH-93 +- Font: Use points instead of halfpoints internally. Conversion to halfpoints done during XML Writing. - @ivanlanin GH-93 +- Paragraph: setTabs() function - @ivanlanin GH-92 +- General: Basic support for TextRun on ODT and RTF - @ivanlanin GH-99 +- Reader: Basic Reader for Word2007 - @ivanlanin GH-104 +- TextRun: Allow Text Break in Text Run - @bskrtich GH-109 +- General: Support for East Asian fontstyle - @jhfangying GH-111 GH-118 +- Image: Use exif_imagetype to check image format instead of extension name - @gabrielbull GH-114 +- General: Setting for XMLWriter Compatibility option - @bskrtich GH-103 +- MemoryImage: Allow remote image when allow_url_open = on - @ivanlanin GH-122 +- TextBreak: Allow font and paragraph style for text break - @ivanlanin GH-18 + +### Bugfixes + +- Fixed bug with cell styling - @gabrielbull +- Fixed bug list items inside of cells - @gabrielbull +- Adding a value that contains "&" in a template breaks it - @SiebelsTim GH-51 +- Example in README.md is broken - @Progi1984 GH-89 +- General: PHPWord_Shared_Drawing::centimetersToPixels() conversion - @ivanlanin GH-94 +- Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin GH-125 + +### Miscellaneous + +- UnitTests - @Progi1984 + +## 0.7.0 - 28 Jan 2014 + +This is the first release after a long development hiatus in [CodePlex](https://phpword.codeplex.com/). This release initialized ODT and RTF Writer, along with some other new features for the existing Word2007 Writer, e.g. tab, multiple header, rowspan and colspan. [Composer](https://packagist.org/packages/phpoffice/phpword) and [Travis](https://travis-ci.org/PHPOffice/PHPWord) were added. + +### Features + +- Implement RTF Writer - @Progi1984 GH-1 +- Implement ODT Writer - @Progi1984 GH-2 +- Word2007: Add rowspan and colspan to cells - @kaystrobach +- Word2007: Support for tab stops - @RLovelett +- Word2007: Support Multiple headers - @RLovelett +- Word2007: Wrapping Styles to Images - @gabrielbull +- Added support for image wrapping style - @gabrielbull + +### Bugfixes + +- "Warning: Invalid error type specified in ...\PHPWord.php on line 226" is thrown when the specified template file is not found - @RomanSyroeshko GH-32 +- PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko GH-34 +- Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko GH-38 + +### Miscellaneous + +- Add superscript/subscript styling in Excel2007 Writer - @MarkBaker +- add indentation support to paragraphs - @deds +- Support for Composer - @Progi1984 GH-27 +- Basic CI with Travis - @Progi1984 +- Added PHPWord_Exception and exception when could not copy the template - @Progi1984 +- IMPROVED: Moved examples out of Classes directory - @Progi1984 +- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo CP-49 diff --git a/samples/Sample_28_Line.php b/samples/Sample_28_Line.php new file mode 100644 index 00000000..5a955702 --- /dev/null +++ b/samples/Sample_28_Line.php @@ -0,0 +1,64 @@ +addSection(); + +// Add Line elements +// See Element/Line.php for all options +$section->addText('Horizontal Line (Inline style):'); +$section->addLine( + array( + 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4), + 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(0), + 'positioning' => 'absolute' + ) +); +$section->addText('Vertical Line (Inline style):'); +$section->addLine( + array( + 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(0), + 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(1), + 'positioning' => 'absolute' + ) +); +// Two text break +$section->addTextBreak(1); + +$section->addText('Positioned Line (red):'); +$section->addLine( + array( + 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4), + 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(1), + 'positioning' => 'absolute', + 'posHorizontalRel' => 'page', + 'posVerticalRel' => 'page', + 'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(10), + 'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(8), + 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, + 'color' => 'red' + ) +); + +$section->addText('Horizontal Formatted Line'); +$section->addLine( + array( + 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(15), + 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(0), + 'positioning' => 'absolute', + 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, + 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, + 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'weight' => 10 + ) +); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 71c5ae2a..6032f33f 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -156,6 +156,19 @@ abstract class AbstractContainer extends AbstractElement } + /** + * Add line element + * + * @param mixed $lineStyle + * @return \PhpOffice\PhpWord\Element\Line + */ + public function addLine($lineStyle = null) + { + return $this->addElement('Line', $lineStyle); + + } + + /** * Add link element * @@ -331,6 +344,7 @@ abstract class AbstractContainer extends AbstractElement 'Image' => $allContainers, 'Object' => $allContainers, 'Field' => $allContainers, + 'Line' => $allContainers, 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php new file mode 100644 index 00000000..eef38914 --- /dev/null +++ b/src/PhpWord/Element/Line.php @@ -0,0 +1,54 @@ +style = $this->setStyle(new LineStyle(), $style); + } + + /** + * Get Image style + * + * @return ImageStyle + */ + public function getStyle() + { + return $this->style; + } +} diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php new file mode 100644 index 00000000..67a4328c --- /dev/null +++ b/src/PhpWord/Style/Line.php @@ -0,0 +1,256 @@ +flip = $value; + } + + /** + * Get flip + * + * @return boolean + */ + public function getFlip() + { + return $this->flip; + } + + /** + * Set connectorType + * + * @param string $value + */ + public function setConnectorType($value = null) + { + $enum = array( + self::CONNECTOR_TYPE_STRAIGHT + ); + $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType); + } + + /** + * Get connectorType + * + * @return string + */ + public function getConnectorType() + { + return $this->connectorType; + } + + /** + * Set weight + * + * @param int $value Weight in points + */ + public function setWeight($value = null) + { + $this->weight = $value; + } + + /** + * Get weight + * + * @return int + */ + public function getWeight() + { + return $this->weight; + } + + /** + * Set color + * + * @param string $value + */ + public function setColor($value = null) + { + $this->color = $value; + } + + /** + * Get color + * + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * Set beginArrow + * + * @param string $value + */ + public function setBeginArrow($value = null) + { + $enum = array( + self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND, + self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL + ); + $this->beginArrow = $this->setEnumVal($value, $enum, $this->beginArrow); + } + + /** + * Get beginArrow + * + * @return string + */ + public function getBeginArrow() + { + return $this->beginArrow; + } + /** + * Set endArrow + * + * @param string $value + */ + public function setEndArrow($value = null) + { + $enum = array( + self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND, + self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL + ); + $this->endArrow = $this->setEnumVal($value, $enum, $this->endArrow); + } + /** + * Get endArrow + * + * @return string + */ + public function getEndArrow() + { + return $this->endArrow; + } + /** + * Set Dash + * + * @param string $value + */ + public function setDash($value = null) + { + $enum = array( + self::DASH_STYLE_DASH, self::DASH_STYLE_DASH_DOT, self::DASH_STYLE_LONG_DASH, + self::DASH_STYLE_LONG_DASH_DOT, self::DASH_STYLE_LONG_DASH_DOT_DOT, self::DASH_STYLE_ROUND_DOT, + self::DASH_STYLE_SQUARE_DOT + ); + $this->dash = $this->setEnumVal($value, $enum, $this->dash); + } + /** + * Get Dash + * + * @return string + */ + public function getDash() + { + return $this->dash; + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php new file mode 100644 index 00000000..41171205 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -0,0 +1,84 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof LineElement) { + return; + } + + $style = $element->getStyle(); + $styleWriter = new LineStyleWriter($xmlWriter, $style); + + $id=$element->getElementIndex(); + if (!$this->withoutP) { + $xmlWriter->startElement('w:p'); + $styleWriter->writeAlignment(); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:pict'); + if ($id==1) { //shapetype could be defined for each line separately, but then a unique id would be necessary + $xmlWriter->startElement('v:shapetype'); + $xmlWriter->writeAttribute('id', '_x0000_t32'); + $xmlWriter->writeAttribute('coordsize', '21600,21600'); + $xmlWriter->writeAttribute('o:spt', '32'); + $xmlWriter->writeAttribute('o:oned', 't'); + $xmlWriter->writeAttribute('path', 'm,l21600,21600e'); + $xmlWriter->writeAttribute('filled', 'f'); + $xmlWriter->startElement('v:path'); + $xmlWriter->writeAttribute('arrowok', 't'); + $xmlWriter->writeAttribute('fillok', 'f'); + $xmlWriter->writeAttribute('o:connecttype', 'none'); + $xmlWriter->endElement(); // v:path + $xmlWriter->startElement('o:lock'); + $xmlWriter->writeAttribute('v:ext', 'edit'); + $xmlWriter->writeAttribute('shapetype', 't'); + $xmlWriter->endElement(); // o:lock + $xmlWriter->endElement(); // v:shapetype + } + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('id', sprintf('_x0000_s1%1$03d', $id)); + $xmlWriter->writeAttribute('type', '#_x0000_t32'); //type should correspond to shapetype id + $styleWriter->write(); + $styleWriter->writeStroke(); + $styleWriter->writeW10Wrap(); + $xmlWriter->endElement(); // v:shape + $xmlWriter->endElement(); // w:pict + $xmlWriter->endElement(); // w:r + + if (!$this->withoutP) { + $xmlWriter->endElement(); // w:p + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php new file mode 100644 index 00000000..dbf7773f --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -0,0 +1,180 @@ +getStyle(); + if (!$style instanceof LineStyle) { + return; + } + $this->writeStyle($style); + } + + /** + * Write style attribute + * + * Copied function from Image/writeStyle in order to override getElementStyle + */ + protected function writeStyle(ImageStyle $style) + { + $xmlWriter = $this->getXmlWriter(); + + // Default style array + $styleArray = array( + 'mso-width-percent' => '0', + 'mso-height-percent' => '0', + 'mso-width-relative' => 'margin', + 'mso-height-relative' => 'margin', + ); + $styleArray = array_merge($styleArray, $this->getElementStyle($style)); + + // Absolute/relative positioning + $positioning = $style->getPositioning(); + $styleArray['position'] = $positioning; + if ($positioning !== null) { + $styleArray['mso-position-horizontal'] = $style->getPosHorizontal(); + $styleArray['mso-position-vertical'] = $style->getPosVertical(); + $styleArray['mso-position-horizontal-relative'] = $style->getPosHorizontalRel(); + $styleArray['mso-position-vertical-relative'] = $style->getPosVerticalRel(); + } + + // Wrapping style + $wrapping = $style->getWrappingStyle(); + if ($wrapping == LineStyle::WRAPPING_STYLE_INLINE) { + // Nothing to do when inline + } elseif ($wrapping == LineStyle::WRAPPING_STYLE_BEHIND) { + $styleArray['z-index'] = -251658752; + } else { + $styleArray['z-index'] = 251659264; + $styleArray['mso-position-horizontal'] = 'absolute'; + $styleArray['mso-position-vertical'] = 'absolute'; + } + + // w10 wrapping + if ($wrapping == LineStyle::WRAPPING_STYLE_SQUARE) { + $this->w10wrap = 'square'; + } elseif ($wrapping == LineStyle::WRAPPING_STYLE_TIGHT) { + $this->w10wrap = 'tight'; + } + + $imageStyle = $this->assembleStyle($styleArray); + + $xmlWriter->writeAttribute('style', $imageStyle); + $xmlWriter->writeAttribute('o:connectortype', $style->getConnectorType()); + + // Weight + $weight = $style->getWeight(); + if ($weight !== null) { + $xmlWriter->writeAttribute('strokeweight', $weight . 'pt'); + } + + // Color + $color = $style->getColor(); + if ($color !== null) { + $xmlWriter->writeAttribute('strokecolor', $color); + } + } + + /** + * Get element style + * + * @param \PhpOffice\PhpWord\Style\Image $style + * @return array + */ + private function getElementStyle(LineStyle $style) + { + $styles = array(); + $styleValues = array( + 'width' => $style->getWidth(), + 'height' => $style->getHeight(), + 'margin-top' => $style->getMarginTop(), + 'margin-left' => $style->getMarginLeft() + ); + foreach ($styleValues as $key => $value) { + if (!is_null($value)) { + $styles[$key] = $value . 'px'; + } + } + if ($style->getFlip()) { + $styles['flip']='y'; + } + + return $styles; + } + + public function writeStroke() + { + $style = $this->getStyle(); + $xmlWriter = $this->getXmlWriter(); + + $dash = $style->getDash(); + $beginArrow = $style->getBeginArrow(); + $endArrow = $style->getEndArrow(); + + if (($dash !== null) || ($beginArrow !== null) || ($endArrow !== null)) { + $xmlWriter->startElement('v:stroke'); + if ($beginArrow !== null) { + $xmlWriter->writeAttribute('startarrow', $beginArrow); + } + if ($endArrow !== null) { + $xmlWriter->writeAttribute('endarrow', $endArrow); + } + if ($dash !==null) { + switch ($dash) { + case LineStyle::DASH_STYLE_DASH: + $xmlWriter->writeAttribute('dashstyle', 'dash'); + break; + case LineStyle::DASH_STYLE_ROUND_DOT: + $xmlWriter->writeAttribute('dashstyle', '1 1'); + $xmlWriter->writeAttribute('endcap', 'round'); + break; + case LineStyle::DASH_STYLE_SQUARE_DOT: + $xmlWriter->writeAttribute('dashstyle', '1 1'); + break; + case LineStyle::DASH_STYLE_DASH_DOT: + $xmlWriter->writeAttribute('dashstyle', 'dashDot'); + break; + case LineStyle::DASH_STYLE_LONG_DASH: + $xmlWriter->writeAttribute('dashstyle', 'longDash'); + break; + case LineStyle::DASH_STYLE_LONG_DASH_DOT: + $xmlWriter->writeAttribute('dashstyle', 'longDashDot'); + break; + case LineStyle::DASH_STYLE_LONG_DASH_DOT_DOT: + $xmlWriter->writeAttribute('dashstyle', 'longDashDotDot'); + break; + } + } + $xmlWriter->endElement(); //v:stroke + } + } +} diff --git a/tests/PhpWord/Tests/Element/LineTest.php b/tests/PhpWord/Tests/Element/LineTest.php new file mode 100644 index 00000000..429f9df6 --- /dev/null +++ b/tests/PhpWord/Tests/Element/LineTest.php @@ -0,0 +1,76 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\Line', $oLine); + $this->assertEquals($oLine->getStyle(), null); + } + + /** + * Get style name + */ + public function testStyleText() + { + $oLine = new Line('lineStyle'); + + $this->assertEquals($oLine->getStyle(), 'lineStyle'); + } + + /** + * Get style array + */ + public function testStyleArray() + { + $oLine = new Line( + array( + 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(14), + 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4), + 'positioning' => 'absolute', + 'posHorizontalRel' => 'page', + 'posVerticalRel' => 'page', + 'flip' => true, + 'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(5), + 'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3), + 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, + 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, + 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, + 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'weight' => 10 + ) + ); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Line', $oLine->getStyle()); + } +} diff --git a/tests/PhpWord/Tests/Style/LineTest.php b/tests/PhpWord/Tests/Style/LineTest.php new file mode 100644 index 00000000..92756e24 --- /dev/null +++ b/tests/PhpWord/Tests/Style/LineTest.php @@ -0,0 +1,153 @@ + true, + 'connectorType' => \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT, + 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, + 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, + 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'weight' => 10, + 'color' => 'red' + ); + foreach ($properties as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertEquals($value, $object->$get()); + } + } + + /** + * Test setStyleValue method + */ + public function testSetStyleValue() + { + $object = new Line(); + + $properties = array( + 'flip' => true, + 'connectorType' => \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT, + 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, + 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, + 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'weight' => 10, + 'color' => 'red' + ); + foreach ($properties as $key => $value) { + $get = "get{$key}"; + $object->setStyleValue("{$key}", $value); + $this->assertEquals($value, $object->$get()); + } + } + + /** + * Test set/get flip + */ + public function testSetGetFlip() + { + $expected=true; + $object = new Line(); + $object->setFlip($expected); + $this->assertEquals($expected, $object->getFlip()); + } + + /** + * Test set/get connectorType + */ + public function testSetGetConnectorType() + { + $expected=\PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT; + $object = new Line(); + $object->setConnectorType($expected); + $this->assertEquals($expected, $object->getConnectorType()); + } + + /** + * Test set/get weight + */ + public function testSetGetWeight() + { + $expected=10; + $object = new Line(); + $object->setWeight($expected); + $this->assertEquals($expected, $object->getWeight()); + } + + /** + * Test set/get color + */ + public function testSetGetColor() + { + $expected='red'; + $object = new Line(); + $object->setColor($expected); + $this->assertEquals($expected, $object->getColor()); + } + + /** + * Test set/get dash + */ + public function testSetGetDash() + { + $expected=\PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT; + $object = new Line(); + $object->setDash($expected); + $this->assertEquals($expected, $object->getDash()); + } + + /** + * Test set/get beginArrow + */ + public function testSetGetBeginArrow() + { + $expected=\PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK; + $object = new Line(); + $object->setBeginArrow($expected); + $this->assertEquals($expected, $object->getBeginArrow()); + } + + /** + * Test set/get endArrow + */ + public function testSetGetEndArrow() + { + $expected=\PhpOffice\PhpWord\Style\Line::ARROW_STYLE_CLASSIC; + $object = new Line(); + $object->setEndArrow($expected); + $this->assertEquals($expected, $object->getEndArrow()); + } +} From 54af93a20ae43787d3491730686ab2e411172dc8 Mon Sep 17 00:00:00 2001 From: Bas-Jan 't Jong Date: Thu, 29 May 2014 17:11:54 +0200 Subject: [PATCH 217/326] Fixed some Travis build errors --- src/PhpWord/Style/Line.php | 2 +- src/PhpWord/Writer/Word2007/Style/Line.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index 67a4328c..94bc2ea8 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -117,7 +117,7 @@ class Line extends Image * * @return boolean */ - public function getFlip() + public function isFlip() { return $this->flip; } diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index dbf7773f..a6638d96 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -124,13 +124,17 @@ class Line extends Image $styles[$key] = $value . 'px'; } } - if ($style->getFlip()) { + if ($style->isFlip()) { $styles['flip']='y'; } return $styles; } + /** + * Write Line stroke + * + */ public function writeStroke() { $style = $this->getStyle(); From 010378787306c7abdf93819b47d585f0826c5f64 Mon Sep 17 00:00:00 2001 From: Bas-Jan 't Jong Date: Thu, 29 May 2014 17:44:14 +0200 Subject: [PATCH 218/326] Second attempt to resolve Travis build errors --- src/PhpWord/Writer/Word2007/Style/Line.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index a6638d96..1e4448a8 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -36,7 +36,7 @@ class Line extends Image if (!$style instanceof LineStyle) { return; } - $this->writeStyle($style); + $this->writeLineStyle($style); } /** @@ -44,7 +44,7 @@ class Line extends Image * * Copied function from Image/writeStyle in order to override getElementStyle */ - protected function writeStyle(ImageStyle $style) + protected function writeLineStyle(LineStyle $style) { $xmlWriter = $this->getXmlWriter(); From 748e16473d09797f7ca0248d9b80a41eda66c5f7 Mon Sep 17 00:00:00 2001 From: Bas-Jan 't Jong Date: Thu, 29 May 2014 18:07:01 +0200 Subject: [PATCH 219/326] Final try to resolve Travis build errors --- src/PhpWord/Writer/Word2007/Element/Line.php | 6 +++--- tests/PhpWord/Tests/Style/LineTest.php | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index 41171205..ea202633 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -41,14 +41,14 @@ class Line extends AbstractElement $style = $element->getStyle(); $styleWriter = new LineStyleWriter($xmlWriter, $style); - $id=$element->getElementIndex(); + $elementId=$element->getElementIndex(); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); - if ($id==1) { //shapetype could be defined for each line separately, but then a unique id would be necessary + if ($elementId==1) { //shapetype could be defined for each line separately, but then a unique id would be necessary $xmlWriter->startElement('v:shapetype'); $xmlWriter->writeAttribute('id', '_x0000_t32'); $xmlWriter->writeAttribute('coordsize', '21600,21600'); @@ -68,7 +68,7 @@ class Line extends AbstractElement $xmlWriter->endElement(); // v:shapetype } $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('id', sprintf('_x0000_s1%1$03d', $id)); + $xmlWriter->writeAttribute('id', sprintf('_x0000_s1%1$03d', $elementId)); $xmlWriter->writeAttribute('type', '#_x0000_t32'); //type should correspond to shapetype id $styleWriter->write(); $styleWriter->writeStroke(); diff --git a/tests/PhpWord/Tests/Style/LineTest.php b/tests/PhpWord/Tests/Style/LineTest.php index 92756e24..02d5ba16 100644 --- a/tests/PhpWord/Tests/Style/LineTest.php +++ b/tests/PhpWord/Tests/Style/LineTest.php @@ -35,7 +35,6 @@ class LineTest extends \PHPUnit_Framework_TestCase $object = new Line(); $properties = array( - 'flip' => true, 'connectorType' => \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT, 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, @@ -59,7 +58,6 @@ class LineTest extends \PHPUnit_Framework_TestCase $object = new Line(); $properties = array( - 'flip' => true, 'connectorType' => \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT, 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, @@ -82,7 +80,7 @@ class LineTest extends \PHPUnit_Framework_TestCase $expected=true; $object = new Line(); $object->setFlip($expected); - $this->assertEquals($expected, $object->getFlip()); + $this->assertEquals($expected, $object->isFlip()); } /** From a57b28de8f5edb1a4b79581d54d2a359b05fa704 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 30 May 2014 01:05:55 +0700 Subject: [PATCH 220/326] Some adjustments for the new `Line` element #253 --- CHANGELOG.md | 6 +- CHANGELOG.md~ | 268 ------------------ docs/elements.rst | 7 + docs/src/documentation.md | 6 + ...{Sample_28_Line.php => Sample_29_Line.php} | 0 src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/Field.php | 3 + src/PhpWord/Element/Line.php | 11 +- src/PhpWord/Style/Line.php | 142 ++++++---- src/PhpWord/Writer/Word2007/Element/Line.php | 14 +- src/PhpWord/Writer/Word2007/Style/Image.php | 91 +++--- src/PhpWord/Writer/Word2007/Style/Line.php | 160 +++-------- .../Tests/Writer/Word2007/ElementTest.php | 3 +- .../Writer/Word2007/Part/DocumentTest.php | 11 + .../Tests/Writer/Word2007/StyleTest.php | 3 +- 15 files changed, 219 insertions(+), 508 deletions(-) delete mode 100644 CHANGELOG.md~ rename samples/{Sample_28_Line.php => Sample_29_Line.php} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index a322b2e8..2325b587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.11.0 - Not yet released -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, Line and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. ### Features @@ -30,8 +30,8 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three - RTF Writer: Ability to write document properties - @ivanlanin - RTF Writer: Ability to write image - @ivanlanin - Element: New `Field` element - @basjan GH-251 -- Element: New `Line` element - @basjan -- RTF Reader: Basic RTF reader - @ivanlanin GH-72 +- RTF Reader: Basic RTF reader - @ivanlanin GH-72 GH-252 +- Element: New `Line` element - @basjan GH-253 ### Bugfixes diff --git a/CHANGELOG.md~ b/CHANGELOG.md~ deleted file mode 100644 index 0ccba8cc..00000000 --- a/CHANGELOG.md~ +++ /dev/null @@ -1,268 +0,0 @@ -# Changelog - -This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. - -## 0.11.0 - Not yet released - -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Three new elements were added: TextBox, ListItemRun, and Field. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. - -### Features - -- Image: Ability to define relative and absolute positioning - @basjan GH-217 -- Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin GH-219 -- Element: New `TextBox` element - @basjan @ivanlanin GH-228 GH-229 GH-231 -- HTML: Ability to add elements to PHPWord object via html - @basjan GH-231 -- Element: New `ListItemRun` element that can add a list item with inline formatting like a textrun - @basjan GH-235 -- Table: Ability to add table inside a cell (nested table) - @ivanlanin GH-149 -- RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin GH-158 -- Table: Ability to define table width (in percent and twip) and position - @ivanlanin GH-237 -- RTF Writer: Ability to add links and page breaks in RTF - @ivanlanin GH-196 -- ListItemRun: Remove fontStyle parameter because ListItemRun is inherited from TextRun and TextRun doesn't have fontStyle - @ivanlanin -- Config: Ability to use a config file to store various common settings - @ivanlanin GH-200 -- ODT Writer: Enable inline font style in TextRun - @ivanlanin -- ODT Writer: Enable underline, strike/doublestrike, smallcaps/allcaps, superscript/subscript font style - @ivanlanin -- ODT Writer: Enable section and column - @ivanlanin -- PDF Writer: Add TCPDF and mPDF as optional PDF renderer library - @ivanlanin -- ODT Writer: Enable title element and custom document properties - @ivanlanin -- ODT Reader: Ability to read standard and custom document properties - @ivanlanin -- Word2007 Writer: Enable the missing custom document properties writer - @ivanlanin -- Image: Enable "image float left" - @ivanlanin GH-244 -- RTF Writer: Ability to write document properties - @ivanlanin -- RTF Writer: Ability to write image - @ivanlanin -- Element: New `Field` element - @basjan GH-251 -- RTF Reader: Basic RTF reader - @ivanlanin GH-72 - -### Bugfixes - -- Header: All images added to the second header were assigned to the first header - @basjan GH-222 -- Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan GH-233 GH-234 -- PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin GH-150 -- Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin GH-248 - -### Deprecated - -- Static classes `Footnotes`, `Endnotes`, and `TOC` -- `Writer\Word2007\Part`: `Numbering::writeNumbering()`, `Settings::writeSettings()`, `WebSettings::writeWebSettings()`, `ContentTypes::writeContentTypes()`, `Styles::writeStyles()`, `Document::writeDocument()` all changed into `write()` -- `Writer\Word2007\Part\DocProps`: Split into `Writer\Word2007\Part\DocPropsCore` and `Writer\Word2007\Part\DocPropsApp` -- `Element\Title::getBookmarkId()` replaced by `Element\Title::getRelationId()` -- `Writer\HTML::writeDocument`: Replaced by `Writer\HTML::getContent` - -### Miscellaneous - -- License: Change the project license from LGPL 2.1 into LGPL 3.0 - GH-211 -- Word2007 Writer: New `Style\Image` class - @ivanlanin -- Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin GH-206 -- QA: Reactivate `phpcpd` and `phpmd` on Travis - @ivanlanin -- Refactor: PHPMD recommendation: Change all `get...` method that returns `boolean` into `is...` or `has...` - @ivanlanin -- Docs: Create gh-pages branch for API documentation - @Progi1984 GH-154 -- QA: Add `.scrutinizer.yml` and include `composer.lock` for preparation to Scrutinizer - @ivanlanin GH-186 -- Writer: Refactor writer parts using composite pattern - @ivanlanin -- Docs: Show code quality and test code coverage badge on README -- Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin -- Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin - -## 0.10.1 - 21 May 2014 - -This is a bugfix release for `php-zip` requirement in Composer. - -- Change Composer requirements for php-zip from `require` to `suggest` - @bskrtich GH-246 - -## 0.10.0 - 4 May 2014 - -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled. Basic ODText reader is introduced. - -### Features - -- Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184 -- Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 GH-183 -- Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin -- Footnote: Ability to style footnote reference mark by using `FootnoteReference` style - @ivanlanin -- Font: Add `bgColor` to font style to define background using HEX color - @jcarignan GH-168 -- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168 -- Element: New `CheckBox` element for sections and table cells - @ozilion GH-156 -- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 -- Template: Ability to find & replace variables in headers & footers - @dgudgeon GH-190 -- Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira GH-191 -- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb GH-189 -- Table: Ability to add footnote in table cell - @ivanlanin GH-187 -- Footnote: Ability to add image in footnote - @ivanlanin GH-187 -- ListItem: Ability to add list item in header/footer - @ivanlanin GH-187 -- CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 -- Link: Ability to add link in header/footer - @ivanlanin GH-187 -- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 -- Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 -- General: Add `Style::resetStyles()` - @ivanlanin GH-187 -- DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image, and title - @ivanlanin -- Endnote: Ability to add endnotes - @ivanlanin -- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 -- ODT Writer: Basic table writing support - @ivanlanin -- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 -- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin GH-203 GH-67 GH-147 -- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68 -- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin -- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin -- ODT Writer: Basic image writing - @ivanlanin -- ODT Writer: Link writing - @ivanlanin -- ODT Reader: Basic ODText Reader - @ivanlanin GH-71 -- Section: Ability to define gutter and line numbering - @ivanlanin -- Font: Small caps, all caps, and double strikethrough - @ivanlanin GH-151 -- Settings: Ability to use measurement unit other than twips with `setMeasurementUnit` - @ivanlanin GH-199 -- Style: Remove `bgColor` from `Font`, `Table`, and `Cell` and put it into the new `Shading` style - @ivanlanin -- Style: New `Indentation` and `Spacing` style - @ivanlanin -- Paragraph: Ability to define first line and right indentation - @ivanlanin - -### Bugfixes - -- Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170 -- Documentation: Error in a function - @theBeerNut GH-195 - -### Deprecated - -- `createTextRun` replaced by `addTextRun` -- `createFootnote` replaced by `addFootnote` -- `createHeader` replaced by `addHeader` -- `createFooter` replaced by `addFooter` -- `createSection` replaced by `addSection` -- `Element\Footnote::getReferenceId` replaced by `Element\AbstractElement::getRelationId` -- `Element\Footnote::setReferenceId` replaced by `Element\AbstractElement::setRelationId` -- `Footnote::addFootnoteLinkElement` replaced by `Media::addElement` -- `Footnote::getFootnoteLinkElements` replaced by `Media::getElements` -- All current methods on `Media` -- `Element\Link::getLinkSrc` replaced by `Element\Link::getTarget` -- `Element\Link::getLinkName` replaced by `Element\Link::getText` -- `Style\Cell::getDefaultBorderColor` - -### Miscellaneous - -- Documentation: Simplify page level docblock - @ivanlanin GH-179 -- Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin GH-160 -- General: Refactor folders: `Element` and `Exception` - @ivanlanin GH-187 -- General: Remove legacy `HashTable` and `Shared\ZipStreamWrapper` and all related properties/methods - @ivanlanin GH-187 -- Element: New `AbstractElement` abstract class - @ivanlanin GH-187 -- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 -- General: Remove underscore prefix from all private properties name - @ivanlanin GH-187 -- General: Move Section `Settings` to `Style\Section` - @ivanlanin GH-187 -- General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin GH-187 -- Style: New `Style\AbstractStyle` abstract class - @ivanlanin GH-187 -- Writer: New 'ODText\Base` class - @ivanlanin GH-187 -- General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin -- General: Add some unit tests for Shared & Element (100%!) - @Progi1984 -- Test: Add some samples and tests for image wrapping style - @brunocasado GH-59 -- Refactor: Remove Style\Tabs - @ivanlanin -- Refactor: Apply composite pattern for writers - @ivanlanin -- Refactor: Split `AbstractContainer` from `AbstractElement` - @ivanlanin -- Refactor: Apply composite pattern for Word2007 reader - @ivanlanin - -## 0.9.1 - 27 Mar 2014 - -This is a bugfix release for PSR-4 compatibility. - -- Fixed PSR-4 composer autoloader - @AntonTyutin - -## 0.9.0 - 26 Mar 2014 - -This release marked the transformation to namespaces (PHP 5.3+). - -### Features - -- Image: Ability to use remote or GD images using `addImage()` on sections, headers, footer, cells, and textruns - @ivanlanin -- Header: Ability to use remote or GD images using `addWatermark()` - @ivanlanin - -### Bugfixes - -- Preserve text doesn't render correctly when the text is not the first word, e.g. 'Page {PAGE}' - @ivanlanin - -### Miscellaneous - -- Move documentation to [Read The Docs](http://phpword.readthedocs.org/en/develop/) - @Progi1984 @ivanlanin GH-82 -- Reorganize and redesign samples folder - @ivanlanin GH-137 -- Use `PhpOffice\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull GH-159 GH-58 -- Restructure folders and change folder name `Classes` to `src` and `Tests` to `test` for PSR compliance - @RomanSyroeshko @gabrielbull -- Compliance to phpDocumentor - @ivanlanin -- Merge Style\TableFull into Style\Table. Style\TableFull is deprecated - @ivanlanin GH-160 -- Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin GH-160 - -## 0.8.1 - 17 Mar 2014 - -This is a bugfix release for image detection functionality. - -- Added fallback for computers that do not have exif_imagetype - @bskrtich, @gabrielbull - -## 0.8.0 - 15 Mar 2014 - -This release merged a lot of improvements from the community. Unit tests introduced in this release and has reached 90% code coverage. - -### Features - -- Template: Permit to save a template generated as a file (PHPWord_Template::saveAs()) - @RomanSyroeshko GH-56 GH-57 -- Word2007: Support sections page numbering - @gabrielbull -- Word2007: Added line height methods to mirror the line height settings in Word in the paragraph styling - @gabrielbull -- Word2007: Added support for page header & page footer height - @JillElaine GH-5 -- General: Add ability to manage line breaks after image insertion - @bskrtich GH-6 GH-66 GH-84 -- Template: Ability to limit number of replacements performed by setValue() method of Template class - @RomanSyroeshko GH-52 GH-53 GH-85 -- Table row: Repeat as header row & allow row to break across pages - @ivanlanin GH-48 GH-86 -- Table: Table width in percentage - @ivanlanin GH-48 GH-86 -- Font: Superscript and subscript - @ivanlanin GH-48 GH-86 -- Paragraph: Hanging paragraph - @ivanlanin GH-48 GH-86 -- Section: Multicolumn and section break - @ivanlanin GH-48 GH-86 -- Template: Ability to apply XSL style sheet to Template - @RomanSyroeshko GH-46 GH-47 GH-83 -- General: PHPWord_Shared_Font::pointSizeToTwips() converter - @ivanlanin GH-87 -- Paragraph: Ability to define normal paragraph style with PHPWord::setNormalStyle() - @ivanlanin GH-87 -- Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next) - @ivanlanin GH-87 -- Clone table rows on the fly when using a template document - @jeroenmoors GH-44 GH-88 -- Initial addition of basic footnote support - @deds GH-16 -- Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before - @ivanlanin GH-92 -- General: PHPWord_Style_Font refactoring - @ivanlanin GH-93 -- Font: Use points instead of halfpoints internally. Conversion to halfpoints done during XML Writing. - @ivanlanin GH-93 -- Paragraph: setTabs() function - @ivanlanin GH-92 -- General: Basic support for TextRun on ODT and RTF - @ivanlanin GH-99 -- Reader: Basic Reader for Word2007 - @ivanlanin GH-104 -- TextRun: Allow Text Break in Text Run - @bskrtich GH-109 -- General: Support for East Asian fontstyle - @jhfangying GH-111 GH-118 -- Image: Use exif_imagetype to check image format instead of extension name - @gabrielbull GH-114 -- General: Setting for XMLWriter Compatibility option - @bskrtich GH-103 -- MemoryImage: Allow remote image when allow_url_open = on - @ivanlanin GH-122 -- TextBreak: Allow font and paragraph style for text break - @ivanlanin GH-18 - -### Bugfixes - -- Fixed bug with cell styling - @gabrielbull -- Fixed bug list items inside of cells - @gabrielbull -- Adding a value that contains "&" in a template breaks it - @SiebelsTim GH-51 -- Example in README.md is broken - @Progi1984 GH-89 -- General: PHPWord_Shared_Drawing::centimetersToPixels() conversion - @ivanlanin GH-94 -- Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin GH-125 - -### Miscellaneous - -- UnitTests - @Progi1984 - -## 0.7.0 - 28 Jan 2014 - -This is the first release after a long development hiatus in [CodePlex](https://phpword.codeplex.com/). This release initialized ODT and RTF Writer, along with some other new features for the existing Word2007 Writer, e.g. tab, multiple header, rowspan and colspan. [Composer](https://packagist.org/packages/phpoffice/phpword) and [Travis](https://travis-ci.org/PHPOffice/PHPWord) were added. - -### Features - -- Implement RTF Writer - @Progi1984 GH-1 -- Implement ODT Writer - @Progi1984 GH-2 -- Word2007: Add rowspan and colspan to cells - @kaystrobach -- Word2007: Support for tab stops - @RLovelett -- Word2007: Support Multiple headers - @RLovelett -- Word2007: Wrapping Styles to Images - @gabrielbull -- Added support for image wrapping style - @gabrielbull - -### Bugfixes - -- "Warning: Invalid error type specified in ...\PHPWord.php on line 226" is thrown when the specified template file is not found - @RomanSyroeshko GH-32 -- PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko GH-34 -- Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko GH-38 - -### Miscellaneous - -- Add superscript/subscript styling in Excel2007 Writer - @MarkBaker -- add indentation support to paragraphs - @deds -- Support for Composer - @Progi1984 GH-27 -- Basic CI with Travis - @Progi1984 -- Added PHPWord_Exception and exception when could not copy the template - @Progi1984 -- IMPROVED: Moved examples out of Classes directory - @Progi1984 -- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo CP-49 diff --git a/docs/elements.rst b/docs/elements.rst index 901832eb..98ab042f 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -45,6 +45,8 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 18 | Field | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 19 | Line | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -487,3 +489,8 @@ Fields ------ To be completed + +Line +------ + +To be completed diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 0259dd8b..0f96ff00 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -35,6 +35,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [Checkboxes](#checkboxes) - [Textboxes](#textboxes) - [Fields](#fields) + - [Lines](#lines) - [Templates](#templates) - [Writers & readers](#writers-readers) - [OOXML](#ooxml) @@ -463,6 +464,7 @@ Below are the matrix of element availability in each container. The column shows | 16 | CheckBox | v | v | v | v | - | - | | 17 | TextBox | v | v | v | v | - | - | | 18 | Field | v | v | v | v | v | v | +| 19 | Line | v | v | v | v | v | v | Legend: @@ -844,6 +846,10 @@ To be completed. To be completed. +## Lines + +To be completed. + # Templates You can create a docx template with included search-patterns that can be replaced by any value you wish. Only single-line values can be replaced. To load a template file, use the `loadTemplate` method. After loading the docx template, you can use the `setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. It is not possible to add new PHPWord elements to a loaded template file. diff --git a/samples/Sample_28_Line.php b/samples/Sample_29_Line.php similarity index 100% rename from samples/Sample_28_Line.php rename to samples/Sample_29_Line.php diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 6032f33f..0f065b41 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -149,11 +149,11 @@ abstract class AbstractContainer extends AbstractElement * @param string $type * @param array $properties * @param array $options + * @return \PhpOffice\PhpWord\Element\Field */ public function addField($type = null, $properties = array(), $options = array()) { return $this->addElement('Field', $type, $properties, $options); - } /** diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 7503dc9b..50f0522f 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -95,6 +95,7 @@ class Field extends AbstractElement * * @param string $type * @return string + * @throws \InvalidArgumentException */ public function setType($type = null) { @@ -123,6 +124,7 @@ class Field extends AbstractElement * * @param array $properties * @return self + * @throws \InvalidArgumentException */ public function setProperties($properties = array()) { @@ -152,6 +154,7 @@ class Field extends AbstractElement * * @param array $options * @return self + * @throws \InvalidArgumentException */ public function setOptions($options = array()) { diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index eef38914..4acca8ed 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -27,25 +27,24 @@ class Line extends AbstractElement /** * Line style * - * @var LineStyle + * @var \PhpOffice\PhpWord\Style\Line */ private $style; - + /** * Create new line element * - * @param string $source * @param mixed $style */ public function __construct($style = null) { $this->style = $this->setStyle(new LineStyle(), $style); } - + /** - * Get Image style + * Get line style * - * @return ImageStyle + * @return \PhpOffice\PhpWord\Style\Line */ public function getStyle() { diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index 94bc2ea8..44f54229 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -51,28 +51,28 @@ class Line extends Image const DASH_STYLE_LONG_DASH = 'longdash'; const DASH_STYLE_LONG_DASH_DOT = 'longdashdot'; const DASH_STYLE_LONG_DASH_DOT_DOT = 'longdashdotdot'; - + /** * flip Line * * @var boolean */ private $flip = false; - + /** * connectorType * * @var string */ private $connectorType = self::CONNECTOR_TYPE_STRAIGHT; - + /** * Line Weight * * @var int */ - private $weight = null; - + private $weight; + /** * Line color * @@ -85,33 +85,22 @@ class Line extends Image * * @var string */ - private $dash = null; - + private $dash; + /** * Begin arrow * * @var string */ - private $beginArrow = null; - + private $beginArrow; + /** * End arrow * * @var string */ - private $endArrow = null; - - - /** - * Set flip - * - * @param boolean $value - */ - public function setFlip($value = null) - { - $this->flip = $value; - } - + private $endArrow; + /** * Get flip * @@ -121,20 +110,20 @@ class Line extends Image { return $this->flip; } - + /** - * Set connectorType + * Set flip * - * @param string $value + * @param boolean $value + * @return self */ - public function setConnectorType($value = null) + public function setFlip($value = false) { - $enum = array( - self::CONNECTOR_TYPE_STRAIGHT - ); - $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType); + $this->flip = $this->setBoolVal($value, $this->flip); + + return $this; } - + /** * Get connectorType * @@ -146,15 +135,21 @@ class Line extends Image } /** - * Set weight + * Set connectorType * - * @param int $value Weight in points + * @param string $value + * @return self */ - public function setWeight($value = null) + public function setConnectorType($value = null) { - $this->weight = $value; + $enum = array( + self::CONNECTOR_TYPE_STRAIGHT + ); + $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType); + + return $this; } - + /** * Get weight * @@ -164,17 +159,20 @@ class Line extends Image { return $this->weight; } - + /** - * Set color + * Set weight * - * @param string $value + * @param int $value Weight in points + * @return self */ - public function setColor($value = null) + public function setWeight($value = null) { - $this->color = $value; + $this->weight = $this->setNumericVal($value, $this->weight); + + return $this; } - + /** * Get color * @@ -184,19 +182,18 @@ class Line extends Image { return $this->color; } - + /** - * Set beginArrow + * Set color * * @param string $value + * @return self */ - public function setBeginArrow($value = null) + public function setColor($value = null) { - $enum = array( - self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND, - self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL - ); - $this->beginArrow = $this->setEnumVal($value, $enum, $this->beginArrow); + $this->color = $value; + + return $this; } /** @@ -208,19 +205,24 @@ class Line extends Image { return $this->beginArrow; } + /** - * Set endArrow + * Set beginArrow * * @param string $value + * @return self */ - public function setEndArrow($value = null) + public function setBeginArrow($value = null) { $enum = array( self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND, self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL ); - $this->endArrow = $this->setEnumVal($value, $enum, $this->endArrow); + $this->beginArrow = $this->setEnumVal($value, $enum, $this->beginArrow); + + return $this; } + /** * Get endArrow * @@ -230,20 +232,24 @@ class Line extends Image { return $this->endArrow; } + /** - * Set Dash + * Set endArrow * * @param string $value + * @return self */ - public function setDash($value = null) + public function setEndArrow($value = null) { $enum = array( - self::DASH_STYLE_DASH, self::DASH_STYLE_DASH_DOT, self::DASH_STYLE_LONG_DASH, - self::DASH_STYLE_LONG_DASH_DOT, self::DASH_STYLE_LONG_DASH_DOT_DOT, self::DASH_STYLE_ROUND_DOT, - self::DASH_STYLE_SQUARE_DOT + self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND, + self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL ); - $this->dash = $this->setEnumVal($value, $enum, $this->dash); + $this->endArrow = $this->setEnumVal($value, $enum, $this->endArrow); + + return $this; } + /** * Get Dash * @@ -253,4 +259,22 @@ class Line extends Image { return $this->dash; } + + /** + * Set Dash + * + * @param string $value + * @return self + */ + public function setDash($value = null) + { + $enum = array( + self::DASH_STYLE_DASH, self::DASH_STYLE_DASH_DOT, self::DASH_STYLE_LONG_DASH, + self::DASH_STYLE_LONG_DASH_DOT, self::DASH_STYLE_LONG_DASH_DOT_DOT, self::DASH_STYLE_ROUND_DOT, + self::DASH_STYLE_SQUARE_DOT + ); + $this->dash = $this->setEnumVal($value, $enum, $this->dash); + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index ea202633..1ae10694 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Element\Line as LineElement; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Line as LineStyleWriter; /** @@ -33,22 +32,23 @@ class Line extends AbstractElement public function write() { $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); + $element = $this->getElement(); if (!$element instanceof LineElement) { return; } - $style = $element->getStyle(); + $style = $element->getStyle(); $styleWriter = new LineStyleWriter($xmlWriter, $style); - - $elementId=$element->getElementIndex(); + + $elementId = $element->getElementIndex(); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); - if ($elementId==1) { //shapetype could be defined for each line separately, but then a unique id would be necessary + // Shapetype could be defined for each line separately, but then a unique id would be necessary + if ($elementId == 1) { $xmlWriter->startElement('v:shapetype'); $xmlWriter->writeAttribute('id', '_x0000_t32'); $xmlWriter->writeAttribute('coordsize', '21600,21600'); @@ -76,7 +76,7 @@ class Line extends AbstractElement $xmlWriter->endElement(); // v:shape $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - + if (!$this->withoutP) { $xmlWriter->endElement(); // w:p } diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index b6b46535..280b569a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -48,50 +48,15 @@ class Image extends AbstractStyle /** * Write style attribute + * + * @param \PhpOffice\PhpWord\Style\Image $style */ - protected function writeStyle(ImageStyle $style) + protected function writeStyle($style) { $xmlWriter = $this->getXmlWriter(); - // Default style array - $styleArray = array( - 'mso-width-percent' => '0', - 'mso-height-percent' => '0', - 'mso-width-relative' => 'margin', - 'mso-height-relative' => 'margin', - ); - $styleArray = array_merge($styleArray, $this->getElementStyle($style)); - - // Absolute/relative positioning - $positioning = $style->getPositioning(); - $styleArray['position'] = $positioning; - if ($positioning !== null) { - $styleArray['mso-position-horizontal'] = $style->getPosHorizontal(); - $styleArray['mso-position-vertical'] = $style->getPosVertical(); - $styleArray['mso-position-horizontal-relative'] = $style->getPosHorizontalRel(); - $styleArray['mso-position-vertical-relative'] = $style->getPosVerticalRel(); - } - - // Wrapping style - $wrapping = $style->getWrappingStyle(); - if ($wrapping == ImageStyle::WRAPPING_STYLE_INLINE) { - // Nothing to do when inline - } elseif ($wrapping == ImageStyle::WRAPPING_STYLE_BEHIND) { - $styleArray['z-index'] = -251658752; - } else { - $styleArray['z-index'] = 251659264; - $styleArray['mso-position-horizontal'] = 'absolute'; - $styleArray['mso-position-vertical'] = 'absolute'; - } - - // w10 wrapping - if ($wrapping == ImageStyle::WRAPPING_STYLE_SQUARE) { - $this->w10wrap = 'square'; - } elseif ($wrapping == ImageStyle::WRAPPING_STYLE_TIGHT) { - $this->w10wrap = 'tight'; - } - - $imageStyle = $this->assembleStyle($styleArray); + $styles = $this->getElementStyle($style); + $imageStyle = $this->assembleStyle($styles); $xmlWriter->writeAttribute('style', $imageStyle); } @@ -134,21 +99,57 @@ class Image extends AbstractStyle * @param \PhpOffice\PhpWord\Style\Image $style * @return array */ - private function getElementStyle(ImageStyle $style) + protected function getElementStyle(ImageStyle $style) { - $styles = array(); - $styleValues = array( + $styles = array( + 'mso-width-percent' => '0', + 'mso-height-percent' => '0', + 'mso-width-relative' => 'margin', + 'mso-height-relative' => 'margin', + ); + + // Dimension + $dimensions = array( 'width' => $style->getWidth(), 'height' => $style->getHeight(), 'margin-top' => $style->getMarginTop(), 'margin-left' => $style->getMarginLeft() ); - foreach ($styleValues as $key => $value) { - if (!is_null($value) && $value != '') { + foreach ($dimensions as $key => $value) { + if ($value !== null) { $styles[$key] = $value . 'px'; } } + // Absolute/relative positioning + $positioning = $style->getPositioning(); + $styles['position'] = $positioning; + if ($positioning !== null) { + $styles['mso-position-horizontal'] = $style->getPosHorizontal(); + $styles['mso-position-vertical'] = $style->getPosVertical(); + $styles['mso-position-horizontal-relative'] = $style->getPosHorizontalRel(); + $styles['mso-position-vertical-relative'] = $style->getPosVerticalRel(); + } + + // Wrapping style + $wrapping = $style->getWrappingStyle(); + if ($wrapping == ImageStyle::WRAPPING_STYLE_INLINE) { + // Nothing to do when inline + } elseif ($wrapping == ImageStyle::WRAPPING_STYLE_BEHIND) { + $styles['z-index'] = -251658752; + } else { + $styles['z-index'] = 251659264; + $styles['mso-position-horizontal'] = 'absolute'; + $styles['mso-position-vertical'] = 'absolute'; + } + + // w10 wrapping + if ($wrapping == ImageStyle::WRAPPING_STYLE_SQUARE) { + $this->w10wrap = 'square'; + } elseif ($wrapping == ImageStyle::WRAPPING_STYLE_TIGHT) { + $this->w10wrap = 'tight'; + } + return $styles; } diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index 1e4448a8..dfecb4b0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -17,9 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; use PhpOffice\PhpWord\Style\Line as LineStyle; -use PhpOffice\PhpWord\Style\Image as ImageStyle; /** * Line style writer @@ -36,148 +34,76 @@ class Line extends Image if (!$style instanceof LineStyle) { return; } - $this->writeLineStyle($style); + $this->writeStyle($style); } - + /** * Write style attribute - * - * Copied function from Image/writeStyle in order to override getElementStyle + * + * @param \PhpOffice\PhpWord\Style\Line $style */ - protected function writeLineStyle(LineStyle $style) + protected function writeStyle($style) { $xmlWriter = $this->getXmlWriter(); - - // Default style array - $styleArray = array( - 'mso-width-percent' => '0', - 'mso-height-percent' => '0', - 'mso-width-relative' => 'margin', - 'mso-height-relative' => 'margin', - ); - $styleArray = array_merge($styleArray, $this->getElementStyle($style)); - - // Absolute/relative positioning - $positioning = $style->getPositioning(); - $styleArray['position'] = $positioning; - if ($positioning !== null) { - $styleArray['mso-position-horizontal'] = $style->getPosHorizontal(); - $styleArray['mso-position-vertical'] = $style->getPosVertical(); - $styleArray['mso-position-horizontal-relative'] = $style->getPosHorizontalRel(); - $styleArray['mso-position-vertical-relative'] = $style->getPosVerticalRel(); + + $styles = $this->getElementStyle($style); + if ($style->isFlip()) { + $styles['flip'] = 'y'; } - - // Wrapping style - $wrapping = $style->getWrappingStyle(); - if ($wrapping == LineStyle::WRAPPING_STYLE_INLINE) { - // Nothing to do when inline - } elseif ($wrapping == LineStyle::WRAPPING_STYLE_BEHIND) { - $styleArray['z-index'] = -251658752; - } else { - $styleArray['z-index'] = 251659264; - $styleArray['mso-position-horizontal'] = 'absolute'; - $styleArray['mso-position-vertical'] = 'absolute'; - } - - // w10 wrapping - if ($wrapping == LineStyle::WRAPPING_STYLE_SQUARE) { - $this->w10wrap = 'square'; - } elseif ($wrapping == LineStyle::WRAPPING_STYLE_TIGHT) { - $this->w10wrap = 'tight'; - } - - $imageStyle = $this->assembleStyle($styleArray); - + $imageStyle = $this->assembleStyle($styles); $xmlWriter->writeAttribute('style', $imageStyle); + + // Connector type $xmlWriter->writeAttribute('o:connectortype', $style->getConnectorType()); - + // Weight $weight = $style->getWeight(); - if ($weight !== null) { - $xmlWriter->writeAttribute('strokeweight', $weight . 'pt'); - } - + $xmlWriter->writeAttributeIf($weight !== null, 'strokeweight', $weight . 'pt'); + // Color $color = $style->getColor(); - if ($color !== null) { - $xmlWriter->writeAttribute('strokecolor', $color); - } + $xmlWriter->writeAttributeIf($color !== null, 'strokecolor', $color); } - - /** - * Get element style - * - * @param \PhpOffice\PhpWord\Style\Image $style - * @return array - */ - private function getElementStyle(LineStyle $style) - { - $styles = array(); - $styleValues = array( - 'width' => $style->getWidth(), - 'height' => $style->getHeight(), - 'margin-top' => $style->getMarginTop(), - 'margin-left' => $style->getMarginLeft() - ); - foreach ($styleValues as $key => $value) { - if (!is_null($value)) { - $styles[$key] = $value . 'px'; - } - } - if ($style->isFlip()) { - $styles['flip']='y'; - } - - return $styles; - } - + /** * Write Line stroke - * */ public function writeStroke() { - $style = $this->getStyle(); $xmlWriter = $this->getXmlWriter(); - + $style = $this->getStyle(); + if (!$style instanceof LineStyle) { + return; + } + $dash = $style->getDash(); $beginArrow = $style->getBeginArrow(); $endArrow = $style->getEndArrow(); - + $dashStyles = array( + LineStyle::DASH_STYLE_DASH => 'dash', + LineStyle::DASH_STYLE_ROUND_DOT => '1 1', + LineStyle::DASH_STYLE_SQUARE_DOT => '1 1', + LineStyle::DASH_STYLE_DASH_DOT => 'dashDot', + LineStyle::DASH_STYLE_LONG_DASH => 'longDash', + LineStyle::DASH_STYLE_LONG_DASH_DOT => 'longDashDot', + LineStyle::DASH_STYLE_LONG_DASH_DOT_DOT => 'longDashDotDot', + ); + if (($dash !== null) || ($beginArrow !== null) || ($endArrow !== null)) { $xmlWriter->startElement('v:stroke'); - if ($beginArrow !== null) { - $xmlWriter->writeAttribute('startarrow', $beginArrow); - } - if ($endArrow !== null) { - $xmlWriter->writeAttribute('endarrow', $endArrow); - } - if ($dash !==null) { - switch ($dash) { - case LineStyle::DASH_STYLE_DASH: - $xmlWriter->writeAttribute('dashstyle', 'dash'); - break; - case LineStyle::DASH_STYLE_ROUND_DOT: - $xmlWriter->writeAttribute('dashstyle', '1 1'); - $xmlWriter->writeAttribute('endcap', 'round'); - break; - case LineStyle::DASH_STYLE_SQUARE_DOT: - $xmlWriter->writeAttribute('dashstyle', '1 1'); - break; - case LineStyle::DASH_STYLE_DASH_DOT: - $xmlWriter->writeAttribute('dashstyle', 'dashDot'); - break; - case LineStyle::DASH_STYLE_LONG_DASH: - $xmlWriter->writeAttribute('dashstyle', 'longDash'); - break; - case LineStyle::DASH_STYLE_LONG_DASH_DOT: - $xmlWriter->writeAttribute('dashstyle', 'longDashDot'); - break; - case LineStyle::DASH_STYLE_LONG_DASH_DOT_DOT: - $xmlWriter->writeAttribute('dashstyle', 'longDashDotDot'); - break; + + $xmlWriter->writeAttributeIf($beginArrow !== null, 'startarrow', $beginArrow); + $xmlWriter->writeAttributeIf($endArrow !== null, 'endarrow', $endArrow); + + if ($dash !== null) { + if (array_key_exists($dash, $dashStyles)) { + $xmlWriter->writeAttribute('dashstyle', $dashStyles[$dash]); + } + if ($dash == LineStyle::DASH_STYLE_ROUND_DOT) { + $xmlWriter->writeAttribute('endcap', 'round'); } } + $xmlWriter->endElement(); //v:stroke } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index ee8b88ae..23ba575b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -30,7 +30,8 @@ class ElementTest extends \PHPUnit_Framework_TestCase { $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', - 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', 'Field' + 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', + 'Field', 'Line' ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 09f7d6a4..9223470e 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -87,6 +87,17 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $section->addField('DATE', array('dateformat'=>'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat', 'SakaEraCalendar')); $section->addField('DATE', array('dateformat'=>'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat', 'LastUsedFormat')); $section->addField('PAGE', array('format'=>'ArabicDash')); + $section->addLine( + array( + 'width' => 10, + 'height' => 10, + 'positioning' => 'absolute', + 'beginArrow' => 'block', + 'endArrow' => 'open', + 'dash' => 'rounddot', + 'weight' => 10 + ) + ); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php index cc722efb..8303e92b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php @@ -30,7 +30,8 @@ class StyleTest extends \PHPUnit_Framework_TestCase { $styles = array( 'Alignment', 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering', - 'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table', 'TextBox' + 'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table', + 'TextBox', 'Line' ); foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style; From 5c2c687efdd0548a6b6dd0a91dffae51c094578c Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 29 May 2014 22:37:10 +0700 Subject: [PATCH 221/326] #193: Heading numbering --- docs/recipes.rst | 24 ++++++++ docs/src/documentation.md | 23 +++++++ samples/Sample_14_ListItem.php | 21 ++++++- src/PhpWord/Style/NumberingLevel.php | 30 ++++++++++ src/PhpWord/Style/Paragraph.php | 60 +++++++++++++++++++ .../Writer/Word2007/Part/Numbering.php | 7 ++- .../Writer/Word2007/Style/Paragraph.php | 19 ++++++ 7 files changed, 180 insertions(+), 4 deletions(-) diff --git a/docs/recipes.rst b/docs/recipes.rst index eef31527..d5678a52 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -41,3 +41,27 @@ Use ``php://output`` as the filename. header('Expires: 0'); $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); $xmlWriter->save("php://output"); + +Create numbered headings +------------------------ + +Define a numbering style and title styles, and match the two styles (with ``pStyle`` and ``numStyle``) like below. + +.. code-block:: php + + $phpWord->addNumberingStyle( + 'hNum', + array('type' => 'multilevel', 'levels' => array( + array('pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'), + array('pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'), + array('pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'), + ) + ) + ); + $phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => 'hNum', 'numLevel' => 0)); + $phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => 'hNum', 'numLevel' => 1)); + $phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => 'hNum', 'numLevel' => 2)); + + $section->addTitle('Heading 1', 1); + $section->addTitle('Heading 2', 2); + $section->addTitle('Heading 3', 3); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 0259dd8b..3d2b4b16 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -980,6 +980,29 @@ $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); $xmlWriter->save("php://output"); ``` +## Create numbered headings + +Define a numbering style and title styles, and match the two styles (with `pStyle` and `numStyle`) like below. + +```php +$phpWord->addNumberingStyle( + 'hNum', + array('type' => 'multilevel', 'levels' => array( + array('pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'), + array('pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'), + array('pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'), + ) + ) +); +$phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => 'hNum', 'numLevel' => 0)); +$phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => 'hNum', 'numLevel' => 1)); +$phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => 'hNum', 'numLevel' => 2)); + +$section->addTitle('Heading 1', 1); +$section->addTitle('Heading 2', 2); +$section->addTitle('Heading 3', 3); +``` + # Frequently asked questions ## Is this the same with PHPWord that I found in CodePlex? diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 892771bc..3a3d34ab 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -18,7 +18,7 @@ $phpWord->addNumberingStyle( array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), ) - ) + ) ); $predefinedMultilevel = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); @@ -66,6 +66,25 @@ $listItemRun->addText('List item 3'); $listItemRun->addText(' underlined', array('underline'=>'dash')); $section->addTextBreak(2); +// Numbered heading + +$phpWord->addNumberingStyle( + 'headingNumbering', + array('type' => 'multilevel', 'levels' => array( + array('pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'), + array('pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'), + array('pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'), + ) + ) +); +$phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => 'headingNumbering', 'numLevel' => 0)); +$phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => 'headingNumbering', 'numLevel' => 1)); +$phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => 'headingNumbering', 'numLevel' => 2)); + +$section->addTitle('Heading 1', 1); +$section->addTitle('Heading 2', 2); +$section->addTitle('Heading 3', 3); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 465231a7..32e61c89 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -56,6 +56,14 @@ class NumberingLevel extends AbstractStyle */ private $restart; + /** + * Related paragraph style + * + * @var string + * @link http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html + */ + private $pStyle; + /** * Content between numbering symbol and paragraph text * @@ -205,6 +213,28 @@ class NumberingLevel extends AbstractStyle return $this; } + /** + * Get related paragraph style + * + * @return string + */ + public function getPStyle() + { + return $this->pStyle; + } + + /** + * Set related paragraph style + * + * @param string $value + * @return self + */ + public function setPStyle($value) + { + $this->pStyle = $value; + return $this; + } + /** * Get suffix * diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index e70833ca..c504e653 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -114,6 +114,20 @@ class Paragraph extends AbstractStyle */ private $alignment; + /** + * Numbering style name + * + * @var string + */ + private $numStyle; + + /** + * Numbering level + * + * @var int + */ + private $numLevel = 0; + /** * Create new instance */ @@ -532,6 +546,52 @@ class Paragraph extends AbstractStyle return $this; } + /** + * Get numbering style name + * + * @return string + */ + public function getNumStyle() + { + return $this->numStyle; + } + + /** + * Set numbering style name + * + * @param string $value + * @return self + */ + public function setNumStyle($value) + { + $this->numStyle = $value; + + return $this; + } + + /** + * Get numbering level + * + * @return int + */ + public function getNumLevel() + { + return $this->numLevel; + } + + /** + * Set numbering level + * + * @param int $value + * @return self + */ + public function setNumLevel($value = 0) + { + $this->numLevel = $this->setIntVal($value, $this->numLevel); + + return $this; + } + /** * Get allow first/last line to display on a separate page setting * diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 05cbf7b9..8f735dd3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -58,7 +58,7 @@ class Numbering extends AbstractPart $levels = $style->getLevels(); $xmlWriter->startElement('w:abstractNum'); - $xmlWriter->writeAttribute('w:abstractNumId', $style->getNumId()); + $xmlWriter->writeAttribute('w:abstractNumId', $style->getIndex()); $xmlWriter->startElement('w:nsid'); $xmlWriter->writeAttribute('w:val', $this->getRandomHexNumber()); @@ -81,9 +81,9 @@ class Numbering extends AbstractPart foreach ($styles as $style) { if ($style instanceof NumberingStyle) { $xmlWriter->startElement('w:num'); - $xmlWriter->writeAttribute('w:numId', $style->getNumId()); + $xmlWriter->writeAttribute('w:numId', $style->getIndex()); $xmlWriter->startElement('w:abstractNumId'); - $xmlWriter->writeAttribute('w:val', $style->getNumId()); + $xmlWriter->writeAttribute('w:val', $style->getIndex()); $xmlWriter->endElement(); // w:abstractNumId $xmlWriter->endElement(); // w:num } @@ -107,6 +107,7 @@ class Numbering extends AbstractPart 'start' => 'start', 'format' => 'numFmt', 'restart' => 'lvlRestart', + 'pStyle' => 'pStyle', 'suffix' => 'suff', 'text' => 'lvlText', 'align' => 'lvlJc' diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 7322fd91..8741c177 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; /** @@ -117,6 +118,24 @@ class Paragraph extends AbstractStyle $xmlWriter->endElement(); } + // Numbering + $numStyleName = $style->getNumStyle(); + $numStyleObject = Style::getStyle($numStyleName); + if ($numStyleName !== null && $numStyleObject !== null) { + $xmlWriter->startElement('w:numPr'); + $xmlWriter->startElement('w:numId'); + $xmlWriter->writeAttribute('w:val', $numStyleObject->getIndex()); + $xmlWriter->endElement(); // w:numId + $xmlWriter->startElement('w:ilvl'); + $xmlWriter->writeAttribute('w:val', $style->getNumLevel()); + $xmlWriter->endElement(); // w:ilvl + $xmlWriter->endElement(); // w:numPr + + $xmlWriter->startElement('w:outlineLvl'); + $xmlWriter->writeAttribute('w:val', $style->getNumLevel()); + $xmlWriter->endElement(); // w:outlineLvl + } + if (!$this->withoutPPR) { $xmlWriter->endElement(); // w:pPr } From 900a96addf574a4762d31f8ae87be4664b6859fa Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 30 May 2014 19:59:57 +0700 Subject: [PATCH 222/326] Bugfix for #236 (OpenOffice crash when opening DOCX) and paragraph style refactoring --- CHANGELOG.md | 5 + src/PhpWord/Style/Paragraph.php | 464 ++++++++++-------- src/PhpWord/Writer/Word2007/Element/TOC.php | 6 +- src/PhpWord/Writer/Word2007/Element/Title.php | 13 +- .../Writer/Word2007/Style/Paragraph.php | 97 ++-- .../Writer/Word2007/Part/DocumentTest.php | 2 - 6 files changed, 338 insertions(+), 249 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2325b587..7f4e6cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Element: New `Field` element - @basjan GH-251 - RTF Reader: Basic RTF reader - @ivanlanin GH-72 GH-252 - Element: New `Line` element - @basjan GH-253 +- Title: Ability to apply numbering in heading - @ivanlanin GH-193 ### Bugfixes @@ -39,6 +40,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan GH-233 GH-234 - PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin GH-150 - Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin GH-248 +- Title: Orphan `w:fldChar` caused OpenOffice to crash when opening DOCX - @ivanlanin GH-236 ### Deprecated @@ -61,6 +63,9 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Docs: Show code quality and test code coverage badge on README - Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin - Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin +- Docs: Create VERSION file - @ivanlanin +- QA: Improve dan update requirement check in `samples` folder - @ivanlanin + ## 0.10.1 - 21 May 2014 diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c504e653..1aacd44f 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -22,6 +22,30 @@ use PhpOffice\PhpWord\Shared\String; /** * Paragraph style + * + * OOXML: + * - General: alignment, outline level + * - Indentation: left, right, firstline, hanging + * - Spacing: before, after, line spacing + * - Pagination: widow control, keep next, keep line, page break before + * - Formatting exception: suppress line numbers, don't hyphenate + * - Textbox options + * - Tabs + * - Shading + * - Borders + * + * OpenOffice: + * - Indents & spacing + * - Alignment + * - Text flow + * - Outline & numbering + * - Tabs + * - Dropcaps + * - Tabs + * - Borders + * - Background + * + * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html */ class Paragraph extends AbstractStyle { @@ -37,20 +61,6 @@ class Paragraph extends AbstractStyle */ protected $aliases = array('line-height' => 'lineHeight'); - /** - * Text line height - * - * @var int - */ - private $lineHeight; - - /** - * Set of Custom Tab Stops - * - * @var \PhpOffice\PhpWord\Style\Tab[] - */ - private $tabs = array(); - /** * Parent style * @@ -65,6 +75,34 @@ class Paragraph extends AbstractStyle */ private $next; + /** + * Alignment + * + * @var \PhpOffice\PhpWord\Style\Alignment + */ + private $alignment; + + /** + * Indentation + * + * @var \PhpOffice\PhpWord\Style\Indentation + */ + private $indentation; + + /** + * Spacing + * + * @var \PhpOffice\PhpWord\Style\Spacing + */ + private $spacing; + + /** + * Text line height + * + * @var int + */ + private $lineHeight; + /** * Allow first/last line to display on a separate page * @@ -93,27 +131,6 @@ class Paragraph extends AbstractStyle */ private $pageBreakBefore = false; - /** - * Indentation - * - * @var \PhpOffice\PhpWord\Style\Indentation - */ - private $indentation; - - /** - * Spacing - * - * @var \PhpOffice\PhpWord\Style\Spacing - */ - private $spacing; - - /** - * Alignment - * - * @var \PhpOffice\PhpWord\Style\Alignment - */ - private $alignment; - /** * Numbering style name * @@ -128,6 +145,13 @@ class Paragraph extends AbstractStyle */ private $numLevel = 0; + /** + * Set of Custom Tab Stops + * + * @var \PhpOffice\PhpWord\Style\Tab[] + */ + private $tabs = array(); + /** * Create new instance */ @@ -155,6 +179,38 @@ class Paragraph extends AbstractStyle return parent::setStyleValue($key, $value); } + /** + * Get style values + * + * An experiment to retrieve all style values in one function. This will + * reduce function call and increase cohesion between functions. Should be + * implemented in all styles. + * + * @return array + */ + public function getStyleValues() + { + return array( + 'name' => $this->getStyleName(), + 'basedOn' => $this->getBasedOn(), + 'next' => $this->getNext(), + 'alignment' => $this->getAlign(), + 'indentation' => $this->getIndentation(), + 'spacing' => $this->getSpace(), + 'pagination' => array( + 'widowControl' => $this->hasWidowControl(), + 'keepNext' => $this->isKeepNext(), + 'keepLines' => $this->isKeepLines(), + 'pageBreak' => $this->hasPageBreakBefore(), + ), + 'numbering' => array( + 'style' => $this->getNumStyle(), + 'level' => $this->getNumLevel(), + ), + 'tabs' => $this->getTabs(), + ); + } + /** * Get alignment * @@ -178,6 +234,150 @@ class Paragraph extends AbstractStyle return $this; } + /** + * Get parent style ID + * + * @return string + */ + public function getBasedOn() + { + return $this->basedOn; + } + + /** + * Set parent style ID + * + * @param string $value + * @return self + */ + public function setBasedOn($value = 'Normal') + { + $this->basedOn = $value; + + return $this; + } + + /** + * Get style for next paragraph + * + * @return string + */ + public function getNext() + { + return $this->next; + } + + /** + * Set style for next paragraph + * + * @param string $value + * @return self + */ + public function setNext($value = null) + { + $this->next = $value; + + return $this; + } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Indentation + */ + public function getIndentation() + { + return $this->indentation; + } + + /** + * Set shading + * + * @param mixed $value + * @return self + */ + public function setIndentation($value = null) + { + $this->setObjectVal($value, 'Indentation', $this->indentation); + + return $this; + } + + /** + * Get indentation + * + * @return int + */ + public function getIndent() + { + if ($this->indentation !== null) { + return $this->indentation->getLeft(); + } else { + return null; + } + } + + /** + * Set indentation + * + * @param int $value + * @return self + */ + public function setIndent($value = null) + { + return $this->setIndentation(array('left' => $value)); + } + + /** + * Get hanging + * + * @return int + */ + public function getHanging() + { + if ($this->indentation !== null) { + return $this->indentation->getHanging(); + } else { + return null; + } + } + + /** + * Set hanging + * + * @param int $value + * @return self + */ + public function setHanging($value = null) + { + return $this->setIndentation(array('hanging' => $value)); + } + + /** + * Get spacing + * + * @return \PhpOffice\PhpWord\Style\Spacing + * @todo Rename to getSpacing in 1.0 + */ + public function getSpace() + { + return $this->spacing; + } + + /** + * Set spacing + * + * @param mixed $value + * @return self + * @todo Rename to setSpacing in 1.0 + */ + public function setSpace($value = null) + { + $this->setObjectVal($value, 'Spacing', $this->spacing); + + return $this; + } + /** * Get space before paragraph * @@ -285,127 +485,6 @@ class Paragraph extends AbstractStyle return $this; } - /** - * Get indentation - * - * @return int - */ - public function getIndent() - { - if ($this->indentation !== null) { - return $this->indentation->getLeft(); - } else { - return null; - } - } - - /** - * Set indentation - * - * @param int $value - * @return self - */ - public function setIndent($value = null) - { - return $this->setIndentation(array('left' => $value)); - } - - /** - * Get hanging - * - * @return int - */ - public function getHanging() - { - if ($this->indentation !== null) { - return $this->indentation->getHanging(); - } else { - return null; - } - } - - /** - * Set hanging - * - * @param int $value - * @return self - */ - public function setHanging($value = null) - { - return $this->setIndentation(array('hanging' => $value)); - } - - /** - * Get tabs - * - * @return \PhpOffice\PhpWord\Style\Tab[] - */ - public function getTabs() - { - return $this->tabs; - } - - /** - * Set tabs - * - * @param array $value - * @return self - */ - public function setTabs($value = null) - { - if (is_array($value)) { - $this->tabs = $value; - } - - return $this; - } - - /** - * Get parent style ID - * - * @return string - */ - public function getBasedOn() - { - return $this->basedOn; - } - - /** - * Set parent style ID - * - * @param string $value - * @return self - */ - public function setBasedOn($value = 'Normal') - { - $this->basedOn = $value; - - return $this; - } - - /** - * Get style for next paragraph - * - * @return string - */ - public function getNext() - { - return $this->next; - } - - /** - * Set style for next paragraph - * - * @param string $value - * @return self - */ - public function setNext($value = null) - { - $this->next = $value; - - return $this; - } - /** * Get allow first/last line to display on a separate page setting * @@ -498,54 +577,6 @@ class Paragraph extends AbstractStyle return $this; } - /** - * Get shading - * - * @return \PhpOffice\PhpWord\Style\Indentation - */ - public function getIndentation() - { - return $this->indentation; - } - - /** - * Set shading - * - * @param mixed $value - * @return self - */ - public function setIndentation($value = null) - { - $this->setObjectVal($value, 'Indentation', $this->indentation); - - return $this; - } - - /** - * Get shading - * - * @return \PhpOffice\PhpWord\Style\Spacing - * @todo Rename to getSpacing in 1.0 - */ - public function getSpace() - { - return $this->spacing; - } - - /** - * Set shading - * - * @param mixed $value - * @return self - * @todo Rename to setSpacing in 1.0 - */ - public function setSpace($value = null) - { - $this->setObjectVal($value, 'Spacing', $this->spacing); - - return $this; - } - /** * Get numbering style name * @@ -592,6 +623,31 @@ class Paragraph extends AbstractStyle return $this; } + /** + * Get tabs + * + * @return \PhpOffice\PhpWord\Style\Tab[] + */ + public function getTabs() + { + return $this->tabs; + } + + /** + * Set tabs + * + * @param array $value + * @return self + */ + public function setTabs($value = null) + { + if (is_array($value)) { + $this->tabs = $value; + } + + return $this; + } + /** * Get allow first/last line to display on a separate page setting * diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 36ef4866..1db2efdd 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -74,7 +74,7 @@ class TOC extends AbstractElement $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); $isObject = ($fontStyle instanceof Font) ? true : false; - $anchor = '_Toc' . ($title->getRelationId() + 252634154); + $rId = $title->getRelationId(); $indent = ($title->getDepth() - 1) * $tocStyle->getIndent(); $xmlWriter->startElement('w:p'); @@ -87,7 +87,7 @@ class TOC extends AbstractElement // Hyperlink $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('w:anchor', $anchor); + $xmlWriter->writeAttribute('w:anchor', "_Toc{$rId}"); $xmlWriter->writeAttribute('w:history', '1'); // Title text @@ -114,7 +114,7 @@ class TOC extends AbstractElement $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw('PAGEREF ' . $anchor . ' \h'); + $xmlWriter->writeRaw("PAGEREF _Toc{$rId} \h"); $xmlWriter->endElement(); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 298bd9b1..144e67ab 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -35,8 +35,6 @@ class Title extends AbstractElement return; } - $rId = $element->getRelationId(); - $anchor = '_Toc' . ($rId + 252634154); $style = $element->getStyle(); $xmlWriter->startElement('w:p'); @@ -49,23 +47,22 @@ class Title extends AbstractElement $xmlWriter->endElement(); } - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $rId = $element->getRelationId(); + // Bookmark start for TOC $xmlWriter->startElement('w:bookmarkStart'); $xmlWriter->writeAttribute('w:id', $rId); - $xmlWriter->writeAttribute('w:name', $anchor); + $xmlWriter->writeAttribute('w:name', "_Toc{$rId}"); $xmlWriter->endElement(); + // Actual text $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:t'); $xmlWriter->writeRaw($this->getText($element->getText())); $xmlWriter->endElement(); $xmlWriter->endElement(); + // Bookmark end $xmlWriter->startElement('w:bookmarkEnd'); $xmlWriter->writeAttribute('w:id', $rId); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 8741c177..4487aa71 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; @@ -74,41 +75,66 @@ class Paragraph extends AbstractStyle return; } $xmlWriter = $this->getXmlWriter(); + $styles = $style->getStyleValues(); if (!$this->withoutPPR) { $xmlWriter->startElement('w:pPr'); } // Style name - $styleName = $style->getStyleName(); - $xmlWriter->writeElementIf(!is_null($styleName), 'w:pStyle', 'w:val', $styleName); + $xmlWriter->writeElementIf($styles['name'] !== null, 'w:pStyle', 'w:val', $styles['name']); // Alignment - $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); + $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $styles['alignment']))); $styleWriter->write(); // Pagination - $xmlWriter->writeElementIf(!$style->hasWidowControl(), 'w:widowControl', 'w:val', '0'); - $xmlWriter->writeElementIf($style->isKeepNext(), 'w:keepNext', 'w:val', '1'); - $xmlWriter->writeElementIf($style->isKeepLines(), 'w:keepLines', 'w:val', '1'); - $xmlWriter->writeElementIf($style->hasPageBreakBefore(), 'w:pageBreakBefore', 'w:val', '1'); + $xmlWriter->writeElementIf($styles['pagination']['widowControl'] === false, 'w:widowControl', 'w:val', '0'); + $xmlWriter->writeElementIf($styles['pagination']['keepNext'] === true, 'w:keepNext', 'w:val', '1'); + $xmlWriter->writeElementIf($styles['pagination']['keepLines'] === true, 'w:keepLines', 'w:val', '1'); + $xmlWriter->writeElementIf($styles['pagination']['pageBreak'] === true, 'w:pageBreakBefore', 'w:val', '1'); - // Indentation - $indentation = $style->getIndentation(); - if (!is_null($indentation)) { - $styleWriter = new Indentation($xmlWriter, $indentation); - $styleWriter->write(); - } - - // Spacing - $spacing = $style->getSpace(); - if (!is_null($spacing)) { - $styleWriter = new Spacing($xmlWriter, $spacing); - $styleWriter->write(); - } + // Indentation & spacing + $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); + $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); // Tabs - $tabs = $style->getTabs(); + $this->writeTabs($xmlWriter, $styles['tabs']); + + // Numbering + $this->writeNumbering($xmlWriter, $styles['numbering']); + + if (!$this->withoutPPR) { + $xmlWriter->endElement(); // w:pPr + } + } + + /** + * Write child style + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $name + * @param string $value + */ + private function writeChildStyle(XMLWriter $xmlWriter, $name, $value) + { + if ($value !== null) { + $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\" . $name; + + /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */ + $writer = new $class($xmlWriter, $value); + $writer->write(); + } + } + + /** + * Write tabs + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param array $tabs + */ + private function writeTabs(XMLWriter $xmlWriter, $tabs) + { if (!empty($tabs)) { $xmlWriter->startElement("w:tabs"); foreach ($tabs as $tab) { @@ -117,28 +143,35 @@ class Paragraph extends AbstractStyle } $xmlWriter->endElement(); } + } - // Numbering - $numStyleName = $style->getNumStyle(); - $numStyleObject = Style::getStyle($numStyleName); - if ($numStyleName !== null && $numStyleObject !== null) { + /** + * Write numbering + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param array $numbering + */ + private function writeNumbering(XMLWriter $xmlWriter, $numbering) + { + $numStyle = $numbering['style']; + $numLevel = $numbering['level']; + + /** @var \PhpOffice\PhpWord\Style\Numbering $numbering */ + $numbering = Style::getStyle($numStyle); + if ($numStyle !== null && $numbering !== null) { $xmlWriter->startElement('w:numPr'); $xmlWriter->startElement('w:numId'); - $xmlWriter->writeAttribute('w:val', $numStyleObject->getIndex()); + $xmlWriter->writeAttribute('w:val', $numbering->getIndex()); $xmlWriter->endElement(); // w:numId $xmlWriter->startElement('w:ilvl'); - $xmlWriter->writeAttribute('w:val', $style->getNumLevel()); + $xmlWriter->writeAttribute('w:val', $numLevel); $xmlWriter->endElement(); // w:ilvl $xmlWriter->endElement(); // w:numPr $xmlWriter->startElement('w:outlineLvl'); - $xmlWriter->writeAttribute('w:val', $style->getNumLevel()); + $xmlWriter->writeAttribute('w:val', $numLevel); $xmlWriter->endElement(); // w:outlineLvl } - - if (!$this->withoutPPR) { - $xmlWriter->endElement(); // w:pPr - } } /** diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 9223470e..e3933557 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -342,8 +342,6 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $element = "/w:document/w:body/w:p/w:pPr/w:pStyle"; $this->assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val')); - $element = "/w:document/w:body/w:p/w:r/w:fldChar"; - $this->assertEquals('end', $doc->getElementAttribute($element, 'w:fldCharType')); } /** From 4f9399899a2281cc1120782911bc88e16f8d93bc Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 30 May 2014 20:44:06 +0700 Subject: [PATCH 223/326] QA: Docblock improvements and -q parameter for phpdoc --- .travis.yml | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 ++ src/PhpWord/Reader/Word2007/Document.php | 1 + src/PhpWord/Shared/Html.php | 4 +++- src/PhpWord/Style/Image.php | 2 ++ src/PhpWord/Style/Paragraph.php | 4 +++- src/PhpWord/Writer/Word2007/Style/Paragraph.php | 7 ++++--- 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63165dbd..73dd68ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ script: ## PHPUnit - phpunit -c ./ --coverage-text --coverage-html ./build/coverage ## PHPDocumentor - - vendor/bin/phpdoc.php -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" + - vendor/bin/phpdoc.php -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" after_script: ## PHPDocumentor diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 8f14daed..a7261d6d 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -437,6 +437,7 @@ abstract class AbstractPart * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $parentNode * @param array $styleDefs + * @ignoreScrutinizerPatch * @return array */ protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = null, $styleDefs = array()) @@ -467,6 +468,7 @@ abstract class AbstractPart * Return style definition based on conversion method * * @param string $method + * @ignoreScrutinizerPatch * @param mixed $attributeValue * @param mixed $expected * @return mixed diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 80d2dde2..be804531 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -99,6 +99,7 @@ class Document extends AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode + * @ignoreScrutinizerPatch * @return array */ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 501d2404..171cfa21 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -242,7 +242,9 @@ class Html $cNodes = $node->childNodes; if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { - self::parseNode($cNode, $newobject, $styles, $data); + if ($newobject instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + self::parseNode($cNode, $newobject, $styles, $data); + } } } } diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 1de51870..3798c1a2 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -245,6 +245,7 @@ class Image extends AbstractStyle /** * Set margin top * + * @ignoreScrutinizerPatch * @param int|float $value * @return self */ @@ -268,6 +269,7 @@ class Image extends AbstractStyle /** * Set margin left * + * @ignoreScrutinizerPatch * @param int|float $value * @return self */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 1aacd44f..32c7f0f8 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -190,7 +190,7 @@ class Paragraph extends AbstractStyle */ public function getStyleValues() { - return array( + $styles = array( 'name' => $this->getStyleName(), 'basedOn' => $this->getBasedOn(), 'next' => $this->getNext(), @@ -209,6 +209,8 @@ class Paragraph extends AbstractStyle ), 'tabs' => $this->getTabs(), ); + + return $styles; } /** diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 4487aa71..f3287700 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -20,6 +20,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; +use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; /** * Paragraph style writer @@ -71,7 +72,7 @@ class Paragraph extends AbstractStyle private function writeStyle() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if (!$style instanceof ParagraphStyle) { return; } $xmlWriter = $this->getXmlWriter(); @@ -114,7 +115,7 @@ class Paragraph extends AbstractStyle * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $name - * @param string $value + * @param mixed $value */ private function writeChildStyle(XMLWriter $xmlWriter, $name, $value) { @@ -131,7 +132,7 @@ class Paragraph extends AbstractStyle * Write tabs * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param array $tabs + * @param \PhpOffice\PhpWord\Style\Tab[] $tabs */ private function writeTabs(XMLWriter $xmlWriter, $tabs) { From 0164e37873bf45f1cac86b6e995c32bf9e9b9b6e Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 31 May 2014 01:30:59 +0700 Subject: [PATCH 224/326] Decompose Shared\Html --- samples/Sample_26_Html.php | 6 +- src/PhpWord/Shared/Html.php | 440 ++++++++++++++++++++------------ src/PhpWord/Style/Paragraph.php | 1 + 3 files changed, 280 insertions(+), 167 deletions(-) diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 58436915..92b3aa49 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -8,7 +8,11 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $html = '

    Adding element via HTML

    '; $html .= '

    Some well formed HTML snippet needs to be used

    '; -$html .= '

    With for example some inline formatting

    '; +$html .= '

    With for example some1 inline formatting1

    '; +$html .= '

    Unordered (bulleted) list:

    '; +$html .= '
    • Item 1
    • Item 2
      • Item 2.1
      • Item 2.1
    '; +$html .= '

    Ordered (numbered) list:

    '; +$html .= '
    1. Item 1
    2. Item 2
    '; \PhpOffice\PhpWord\Shared\Html::addHtml($section, $html); diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 171cfa21..bfe64a25 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -17,8 +17,12 @@ namespace PhpOffice\PhpWord\Shared; +use PhpOffice\PhpWord\Element\AbstractContainer; + /** * Common Html functions + * + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode */ class Html { @@ -27,10 +31,10 @@ class Html * * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $object Where the parts need to be added + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added * @param string $html the code to parse */ - public static function addHtml($object, $html) + public static function addHtml($element, $html) { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, @@ -44,17 +48,17 @@ class Html $node = $dom->getElementsByTagName('body'); - self::parseNode($node->item(0), $object); + self::parseNode($node->item(0), $element); } /** * parse Inline style of a node * * @param \DOMNode $node Node to check on attributes and to compile a style array - * @param array $style is supplied, the inline style attributes are added to the already existing style + * @param array $styles is supplied, the inline style attributes are added to the already existing style * @return array */ - protected static function parseInlineStyle($node, $style = array()) + protected static function parseInlineStyle($node, $styles = array()) { if ($node->nodeType == XML_ELEMENT_NODE) { $attributes = $node->attributes; // get all the attributes(eg: id, class) @@ -62,191 +66,295 @@ class Html foreach ($attributes as $attribute) { switch ($attribute->name) { case 'style': - $properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;")); - foreach ($properties as $property) { - list ($cKey, $cValue) = explode(':', $property, 2); - $cValue = trim($cValue); - switch (trim($cKey)) { - case 'text-decoration': - switch ($cValue) { - case 'underline': - $style['underline'] = 'single'; - break; - case 'line-through': - $style['strikethrough'] = true; - break; - } - break; - case 'text-align': - $style['align'] = $cValue; - break; - case 'color': - $style['color'] = trim($cValue, "#"); - break; - case 'background-color': - $style['bgColor'] = trim($cValue, "#"); - break; - } - } + $styles = self::parseStyle($attribute, $styles); break; } } } - return $style; + return $styles; } /** - * parse a node and add a corresponding element to the object + * Parse a node and add a corresponding element to the parent element * * @param \DOMNode $node node to parse - * @param \PhpOffice\PhpWord\Element\AbstractContainer $object object to add an element corresponding with the node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element object to add an element corresponding with the node * @param array $styles Array with all styles * @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems */ - protected static function parseNode( - $node, - $object, - $styles = array('fontStyle' => array(), 'paragraphStyle' => array(), 'listStyle' => array()), - $data = array() - ) { - $newobject = null; - switch ($node->nodeName) { - case 'p': - $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - - /** - * @todo Think of a clever way of defining header styles, now it is only based on the assumption, that - * Heading1 - Heading6 are already defined somewhere - */ - case 'h1': - $styles['paragraphStyle'] = 'Heading1'; - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - case 'h2': - $styles['paragraphStyle'] = 'Heading2'; - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - case 'h3': - $styles['paragraphStyle'] = 'Heading3'; - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - case 'h4': - $styles['paragraphStyle'] = 'Heading4'; - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - case 'h5': - $styles['paragraphStyle'] = 'Heading5'; - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - case 'h6': - $styles['paragraphStyle'] = 'Heading6'; - $newobject = $object->addTextRun($styles['paragraphStyle']); - break; - case '#text': - $styles['fontStyle'] = self::parseInlineStyle($node, $styles['fontStyle']); - if (method_exists($object, 'addText')) { - $object->addText($node->nodeValue, $styles['fontStyle'], $styles['paragraphStyle']); - } - break; - case 'strong': - $styles['fontStyle']['bold'] = true; - break; - case 'em': - $styles['fontStyle']['italic'] = true; - break; - case 'sup': - $styles['fontStyle']['superScript'] = true; - break; - case 'sub': - $styles['fontStyle']['subScript'] = true; - break; - - /** - * @todo As soon as TableItem, RowItem and CellItem support relative width and height - */ - case 'table': - $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); - $newobject = $object->addTable(); - // if ($attributes->getNamedItem('width') !== null) { - // $newobject->setWidth($attributes->getNamedItem('width')->value); - // } - break; - case 'tr': - /** @var \PhpOffice\PhpWord\Element\Table $object Type hint */ - $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); - $newobject = $object->addRow(); - // if ($attributes->getNamedItem('height') !== null) { - // $newobject->setHeight($attributes->getNamedItem('height')->value); - // } - break; - case 'td': - /** @var \PhpOffice\PhpWord\Element\Row $object Type hint */ - $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); - // if ($attributes->getNamedItem('width') !== null) { - // $newobject=$object->addCell($width=$attributes->getNamedItem('width')->value); - // } else { - // $newobject=$object->addCell(); - // } - $newobject = $object->addCell(); - break; - case 'ul': - if (isset($data['listdepth'])) { - $data['listdepth'] ++; - } else { - $data['listdepth'] = 0; - } - $styles['listStyle']['listType'] = 3; // TYPE_BULLET_FILLED = 3; - break; - case 'ol': - if (isset($data['listdepth'])) { - $data['listdepth'] ++; - } else { - $data['listdepth'] = 0; - } - $styles['listStyle']['listType'] = 7; // TYPE_NUMBER = 7; - break; - - /** - * @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes - */ - case 'li': - $cNodes = $node->childNodes; - if (count($cNodes) > 0) { - $text = ''; - foreach ($cNodes as $cNode) { - if ($cNode->nodeName == '#text') { - $text = $cNode->nodeValue; - } - } - $object->addListItem( - $text, - $data['listdepth'], - $styles['fontStyle'], - $styles['listStyle'], - $styles['paragraphStyle'] - ); - } + protected static function parseNode($node, $element, $styles = array(), $data = array()) + { + // Populate styles array + $styleTypes = array('font', 'paragraph', 'list'); + foreach ($styleTypes as $styleType) { + if (!isset($styles[$styleType])) { + $styles[$styleType] = array(); + } } - if ($newobject === null) { - $newobject = $object; + // Node mapping table + $nodes = array( + // $method $node $element $styles $data $argument1 $argument2 + 'p' => array('Paragraph', $node, $element, $styles, null, null, null), + 'h1' => array('Heading', null, $element, $styles, null, 'Heading1', null), + 'h2' => array('Heading', null, $element, $styles, null, 'Heading2', null), + 'h3' => array('Heading', null, $element, $styles, null, 'Heading3', null), + 'h4' => array('Heading', null, $element, $styles, null, 'Heading4', null), + 'h5' => array('Heading', null, $element, $styles, null, 'Heading5', null), + 'h6' => array('Heading', null, $element, $styles, null, 'Heading6', null), + '#text' => array('Text', $node, $element, $styles, null, null, null), + 'strong' => array('Property', null, null, $styles, null, 'bold', true), + 'em' => array('Property', null, null, $styles, null, 'italic', true), + 'sup' => array('Property', null, null, $styles, null, 'superScript', true), + 'sub' => array('Property', null, null, $styles, null, 'subScript', true), + 'table' => array('Table', $node, $element, $styles, null, 'addTable', true), + 'tr' => array('Table', $node, $element, $styles, null, 'addRow', true), + 'td' => array('Table', $node, $element, $styles, null, 'addCell', true), + 'ul' => array('List', null, null, $styles, $data, 3, null), + 'ol' => array('List', null, null, $styles, $data, 7, null), + 'li' => array('ListItem', $node, $element, $styles, $data, null, null), + ); + + $newElement = null; + $keys = array('node', 'element', 'styles', 'data', 'argument1', 'argument2'); + + if (array_key_exists($node->nodeName, $nodes)) { + + // Execute method based on node mapping table and return $newElement or null + // Arguments are passed by reference + $arguments = array(); + $args = array(); + list($method, $args[0], $args[1], $args[2], $args[3], $args[4], $args[5]) = $nodes[$node->nodeName]; + for ($i = 0; $i <= 5; $i++) { + if ($args[$i] !== null) { + $arguments[$keys[$i]] = &$args[$i]; + } + } + $method = "parse{$method}"; + $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments); + + // Retrieve back variables from arguments + foreach ($keys as $key) { + if (array_key_exists($key, $arguments)) { + $$key = $arguments[$key]; + } + } } - /** - * @todo As soon as ListItem inherits from AbstractContainer or TextRun delete condition - */ + if ($newElement === null) { + $newElement = $element; + } + + self::parseChildNodes($node, $newElement, $styles, $data); + } + + /** + * Parse child nodes + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @param array $data + */ + private static function parseChildNodes($node, $element, $styles, $data) + { if ($node->nodeName != 'li') { $cNodes = $node->childNodes; if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { - if ($newobject instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { - self::parseNode($cNode, $newobject, $styles, $data); + if ($element instanceof AbstractContainer) { + self::parseNode($cNode, $element, $styles, $data); } } } } } + + /** + * Parse paragraph node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @return \PhpOffice\PhpWord\Element\TextRun + */ + private static function parseParagraph($node, $element, &$styles) + { + $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']); + $newElement = $element->addTextRun($styles['paragraph']); + + return $newElement; + } + + /** + * Parse heading node + * + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @param string $argument1 Name of heading style + * @return \PhpOffice\PhpWord\Element\TextRun + * + * @todo Think of a clever way of defining header styles, now it is only based on the assumption, that + * Heading1 - Heading6 are already defined somewhere + */ + private static function parseHeading($element, &$styles, $argument1) + { + $styles['paragraph'] = $argument1; + $newElement = $element->addTextRun($styles['paragraph']); + + return $newElement; + } + + /** + * Parse text node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @return null + */ + private static function parseText($node, $element, &$styles) + { + $styles['font'] = self::parseInlineStyle($node, $styles['font']); + if (method_exists($element, 'addText')) { + $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); + } + + return null; + } + + /** + * Parse property node + * + * @param array $styles + * @param string $argument1 Style name + * @param string $argument2 Style value + * @return null + */ + private static function parseProperty(&$styles, $argument1, $argument2) + { + $styles['font'][$argument1] = $argument2; + + return null; + } + + /** + * Parse table node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @param string $argument1 Method name + * @return \PhpOffice\PhpWord\Element\AbstractContainer $element + * + * @todo As soon as TableItem, RowItem and CellItem support relative width and height + */ + private static function parseTable($node, $element, &$styles, $argument1) + { + $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']); + + $newElement = $element->$argument1(); + + // $attributes = $node->attributes; + // if ($attributes->getNamedItem('width') !== null) { + // $newElement->setWidth($attributes->getNamedItem('width')->value); + // } + + // if ($attributes->getNamedItem('height') !== null) { + // $newElement->setHeight($attributes->getNamedItem('height')->value); + // } + // if ($attributes->getNamedItem('width') !== null) { + // $newElement=$element->addCell($width=$attributes->getNamedItem('width')->value); + // } + + return $newElement; + } + + /** + * Parse list node + * + * @param array $styles + * @param array $data + * @param string $argument1 List type + * @return null + */ + private static function parseList(&$styles, &$data, $argument1) + { + if (isset($data['listdepth'])) { + $data['listdepth']++; + } else { + $data['listdepth'] = 0; + } + $styles['list']['listType'] = $argument1; + + return null; + } + + /** + * Parse list item node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @param array $data + * @return null + * + * @todo This function is almost the same like `parseChildNodes`. Merged? + * @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes + */ + private static function parseListItem($node, $element, &$styles, $data) + { + $cNodes = $node->childNodes; + if (count($cNodes) > 0) { + $text = ''; + foreach ($cNodes as $cNode) { + if ($cNode->nodeName == '#text') { + $text = $cNode->nodeValue; + } + } + $element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']); + } + + return null; + } + + /** + * Parse style + * + * @param \DOMAttr $attribute + * @param array $styles + * @return array + */ + private static function parseStyle($attribute, $styles) + { + $properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;")); + foreach ($properties as $property) { + list($cKey, $cValue) = explode(':', $property, 2); + $cValue = trim($cValue); + switch (trim($cKey)) { + case 'text-decoration': + switch ($cValue) { + case 'underline': + $styles['underline'] = 'single'; + break; + case 'line-through': + $styles['strikethrough'] = true; + break; + } + break; + case 'text-align': + $styles['align'] = $cValue; + break; + case 'color': + $styles['color'] = trim($cValue, "#"); + break; + case 'background-color': + $styles['bgColor'] = trim($cValue, "#"); + break; + } + } + + return $styles; + } } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 32c7f0f8..81673586 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -186,6 +186,7 @@ class Paragraph extends AbstractStyle * reduce function call and increase cohesion between functions. Should be * implemented in all styles. * + * @ignoreScrutinizerPatch * @return array */ public function getStyleValues() From ec85d7d641dc7f6a2f75f0ae81279b0c1c5d23a7 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 31 May 2014 03:06:11 +0700 Subject: [PATCH 225/326] #80: Basic HTML reader --- CHANGELOG.md | 3 +- samples/Sample_30_ReadHTML.php | 15 ++++++ samples/resources/Sample_30_ReadHTML.html | 15 ++++++ src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Reader/HTML.php | 50 ++++++++++++++++++ src/PhpWord/Shared/Html.php | 17 +++++-- tests/PhpWord/Tests/Reader/HTMLTest.php | 51 +++++++++++++++++++ .../Tests/_files/documents/reader.html | 15 ++++++ 8 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 samples/Sample_30_ReadHTML.php create mode 100644 samples/resources/Sample_30_ReadHTML.html create mode 100644 src/PhpWord/Reader/HTML.php create mode 100644 tests/PhpWord/Tests/Reader/HTMLTest.php create mode 100644 tests/PhpWord/Tests/_files/documents/reader.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f4e6cf0..8b36f34a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.11.0 - Not yet released -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF and HTML reader were initiated. ### Features @@ -33,6 +33,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - RTF Reader: Basic RTF reader - @ivanlanin GH-72 GH-252 - Element: New `Line` element - @basjan GH-253 - Title: Ability to apply numbering in heading - @ivanlanin GH-193 +- HTML Reader: Basic HTML reader - @ivanlanin GH-80 ### Bugfixes diff --git a/samples/Sample_30_ReadHTML.php b/samples/Sample_30_ReadHTML.php new file mode 100644 index 00000000..029f8c8c --- /dev/null +++ b/samples/Sample_30_ReadHTML.php @@ -0,0 +1,15 @@ + + + +PHPWord + + +

    Adding element via HTML

    +

    Some well formed HTML snippet needs to be used

    +

    With for example some1 inline formatting1

    +

    Unordered (bulleted) list:

    +
    • Item 1
    • Item 2
      • Item 2.1
      • Item 2.1
    +

    Ordered (numbered) list:

    +
    1. Item 1
    2. Item 2
    + + diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 0d5fe689..1d784962 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -51,7 +51,7 @@ abstract class IOFactory */ public static function createReader($name = 'Word2007') { - if (!in_array($name, array('ReaderInterface', 'Word2007', 'ODText', 'RTF'))) { + if (!in_array($name, array('ReaderInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) { throw new Exception("\"{$name}\" is not a valid reader."); } diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php new file mode 100644 index 00000000..a6582a3f --- /dev/null +++ b/src/PhpWord/Reader/HTML.php @@ -0,0 +1,50 @@ +canRead($docFile)) { + $section = $phpWord->addSection(); + HTMLParser::addHtml($section, file_get_contents($docFile), true); + } else { + throw new \Exception("Cannot read {$docFile}."); + } + + return $phpWord; + } +} diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index bfe64a25..83292a3a 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -32,20 +32,27 @@ class Html * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter * * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added - * @param string $html the code to parse + * @param string $html The code to parse + * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag */ - public static function addHtml($element, $html) + public static function addHtml($element, $html, $fullHTML = false) { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, * which could be applied when such an element occurs in the parseNode function. */ - $html = str_replace(array("\n", "\r"), '', $html); + // Preprocess: remove all line ends, decode HTML entity, and add body tag for HTML fragments + $html = str_replace(array("\n", "\r"), '', $html); + $html = html_entity_decode($html); + if ($fullHTML === false) { + $html = '' . $html . ''; + } + + // Load DOM $dom = new \DOMDocument(); $dom->preserveWhiteSpace = true; - $dom->loadXML('' . html_entity_decode($html) . ''); - + $dom->loadXML($html); $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); diff --git a/tests/PhpWord/Tests/Reader/HTMLTest.php b/tests/PhpWord/Tests/Reader/HTMLTest.php new file mode 100644 index 00000000..cb3dc55c --- /dev/null +++ b/tests/PhpWord/Tests/Reader/HTMLTest.php @@ -0,0 +1,51 @@ +assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + } + + /** + * Test load exception + * + * @expectedException \Exception + * @expectedExceptionMessage Cannot read + */ + public function testLoadException() + { + $filename = __DIR__ . '/../_files/documents/foo.html'; + IOFactory::load($filename, 'HTML'); + } +} diff --git a/tests/PhpWord/Tests/_files/documents/reader.html b/tests/PhpWord/Tests/_files/documents/reader.html new file mode 100644 index 00000000..5593298b --- /dev/null +++ b/tests/PhpWord/Tests/_files/documents/reader.html @@ -0,0 +1,15 @@ + + + +PHPWord + + +

    Adding element via HTML

    +

    Some well formed HTML snippet needs to be used

    +

    With for example some1 inline formatting1

    +

    Unordered (bulleted) list:

    +
    • Item 1
    • Item 2
      • Item 2.1
      • Item 2.1
    +

    Ordered (numbered) list:

    +
    1. Item 1
    2. Item 2
    + + From 022cdeb570519e238247afb0a75ff9b5949d3ef7 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 31 May 2014 03:28:58 +0700 Subject: [PATCH 226/326] Documentation updates and test fix for #254 --- CHANGELOG.md | 2 +- docs/intro.rst | 110 ++++++++++++------------ docs/src/documentation.md | 56 ++++++------ tests/PhpWord/Tests/Shared/HtmlTest.php | 4 +- 4 files changed, 86 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b36f34a..43b5373d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - RTF Reader: Basic RTF reader - @ivanlanin GH-72 GH-252 - Element: New `Line` element - @basjan GH-253 - Title: Ability to apply numbering in heading - @ivanlanin GH-193 -- HTML Reader: Basic HTML reader - @ivanlanin GH-80 +- HTML Reader: Basic HTML reader - @ivanlanin GH-80 GH-254 ### Bugfixes diff --git a/docs/intro.rst b/docs/intro.rst index 3da729e8..94001237 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -117,61 +117,61 @@ Writers Readers ~~~~~~~ -+---------------------------+----------------------+--------+-------+-------+ -| Features | | DOCX | ODT | RTF | -+===========================+======================+========+=======+=======+ -| **Document Properties** | Standard | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Custom | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| **Element Type** | Text | ✓ | ✓ | ✓ | -+---------------------------+----------------------+--------+-------+-------+ -| | Text Run | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Title | ✓ | ✓ | | -+---------------------------+----------------------+--------+-------+-------+ -| | Link | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Preserve Text | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Text Break | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Page Break | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | List | ✓ | ✓ | | -+---------------------------+----------------------+--------+-------+-------+ -| | Table | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Image | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Object | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Watermark | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Table of Contents | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Header | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Footer | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Footnote | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Endnote | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| **Graphs** | 2D basic graphs | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | 2D advanced graphs | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | 3D graphs | | | | -+---------------------------+----------------------+--------+-------+-------+ -| **Math** | OMML support | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | MathML support | | | | -+---------------------------+----------------------+--------+-------+-------+ -| **Bonus** | Encryption | | | | -+---------------------------+----------------------+--------+-------+-------+ -| | Protection | | | | -+---------------------------+----------------------+--------+-------+-------+ ++---------------------------+----------------------+--------+-------+-------+-------+ +| Features | | DOCX | ODT | RTF | HTML | ++===========================+======================+========+=======+=======+=======+ +| **Document Properties** | Standard | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Custom | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Text Run | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Title | ✓ | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Link | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Preserve Text | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Text Break | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Page Break | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | List | ✓ | ✓ | | ✓ | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Table | ✓ | | | ✓ | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Image | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Object | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Watermark | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Table of Contents | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Header | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Footer | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Footnote | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Endnote | ✓ | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| **Graphs** | 2D basic graphs | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | 2D advanced graphs | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | 3D graphs | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| **Math** | OMML support | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | MathML support | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| **Bonus** | Encryption | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ +| | Protection | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+ Contributing ------------ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 9db32c9f..773269a9 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -111,34 +111,34 @@ Below are the supported features for each file formats. ### Readers -| Features | | DOCX | ODT | RTF | -|-------------------------|--------------------|------|-----|-----| -| **Document Properties** | Standard | ✓ | | | -| | Custom | ✓ | | | -| **Element Type** | Text | ✓ | ✓ | ✓ | -| | Text Run | ✓ | | | -| | Title | ✓ | ✓ | | -| | Link | ✓ | | | -| | Preserve Text | ✓ | | | -| | Text Break | ✓ | | | -| | Page Break | ✓ | | | -| | List | ✓ | ✓ | | -| | Table | ✓ | | | -| | Image | ✓ | | | -| | Object | | | | -| | Watermark | | | | -| | Table of Contents | | | | -| | Header | ✓ | | | -| | Footer | ✓ | | | -| | Footnote | ✓ | | | -| | Endnote | ✓ | | | -| **Graphs** | 2D basic graphs | | | | -| | 2D advanced graphs | | | | -| | 3D graphs | | | | -| **Math** | OMML support | | | | -| | MathML support | | | | -| **Bonus** | Encryption | | | | -| | Protection | | | | +| Features | | DOCX | ODT | RTF | HTML| +|-------------------------|--------------------|------|-----|-----|-----| +| **Document Properties** | Standard | ✓ | | | | +| | Custom | ✓ | | | | +| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | +| | Text Run | ✓ | | | | +| | Title | ✓ | ✓ | | | +| | Link | ✓ | | | | +| | Preserve Text | ✓ | | | | +| | Text Break | ✓ | | | | +| | Page Break | ✓ | | | | +| | List | ✓ | ✓ | | ✓ | +| | Table | ✓ | | | ✓ | +| | Image | ✓ | | | | +| | Object | | | | | +| | Watermark | | | | | +| | Table of Contents | | | | | +| | Header | ✓ | | | | +| | Footer | ✓ | | | | +| | Footnote | ✓ | | | | +| | Endnote | ✓ | | | | +| **Graphs** | 2D basic graphs | | | | | +| | 2D advanced graphs | | | | | +| | 3D graphs | | | | | +| **Math** | OMML support | | | | | +| | MathML support | | | | | +| **Bonus** | Encryption | | | | | +| | Protection | | | | | ## Contributing diff --git a/tests/PhpWord/Tests/Shared/HtmlTest.php b/tests/PhpWord/Tests/Shared/HtmlTest.php index 81714432..730600d7 100644 --- a/tests/PhpWord/Tests/Shared/HtmlTest.php +++ b/tests/PhpWord/Tests/Shared/HtmlTest.php @@ -58,8 +58,8 @@ class HtmlTest extends \PHPUnit_Framework_TestCase $section = new Section(1); $content = ''; $content .= '
    HeaderContent
    '; - $content .= '
    • Bullet
    '; + $content .= '
    • Bullet
      • Bullet
    '; $content .= '
    1. Bullet
    '; - Html::addHtml($section, $content, null, array('listdepth' => 2)); + Html::addHtml($section, $content); } } From e7540c079ec8e574cded63447f75a71793e51a83 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 31 May 2014 09:29:09 +0700 Subject: [PATCH 227/326] Add $nestedLevel to elements --- src/PhpWord/Element/AbstractContainer.php | 60 +++++++++++++---------- src/PhpWord/Element/AbstractElement.php | 35 +++++++++++-- src/PhpWord/Element/Row.php | 1 + src/PhpWord/Element/Table.php | 22 ++++----- 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0f065b41..95186749 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -65,9 +65,18 @@ abstract class AbstractContainer extends AbstractElement $reflection = new \ReflectionClass($elementClass); $elementArgs = $args; array_shift($elementArgs); // Shift an element off the beginning of array: the $elementName + /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ $element = $reflection->newInstanceArgs($elementArgs); + // Set nested level + if ($this->container == 'Cell') { + $element->setNestedLevel($this->getNestedLevel() + 1); + } else { + $element->setNestedLevel($this->getNestedLevel()); + } + + // Set relation Id for media collection $mediaContainer = $this->getMediaContainer(); if (in_array($elementName, array('Link', 'Image', 'Object'))) { @@ -143,32 +152,6 @@ abstract class AbstractContainer extends AbstractElement return $this->addElement('TextRun', $paragraphStyle); } - /** - * Add field element - * - * @param string $type - * @param array $properties - * @param array $options - * @return \PhpOffice\PhpWord\Element\Field - */ - public function addField($type = null, $properties = array(), $options = array()) - { - return $this->addElement('Field', $type, $properties, $options); - } - - /** - * Add line element - * - * @param mixed $lineStyle - * @return \PhpOffice\PhpWord\Element\Line - */ - public function addLine($lineStyle = null) - { - return $this->addElement('Line', $lineStyle); - - } - - /** * Add link element * @@ -323,6 +306,31 @@ abstract class AbstractContainer extends AbstractElement return $this->addElement('TextBox', $style); } + /** + * Add field element + * + * @param string $type + * @param array $properties + * @param array $options + * @return \PhpOffice\PhpWord\Element\Field + */ + public function addField($type = null, $properties = array(), $options = array()) + { + return $this->addElement('Field', $type, $properties, $options); + } + + /** + * Add line element + * + * @param mixed $lineStyle + * @return \PhpOffice\PhpWord\Element\Line + */ + public function addLine($lineStyle = null) + { + return $this->addElement('Line', $lineStyle); + + } + /** * Check if a method is allowed for the current container * diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 45311364..ca45ef23 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -84,6 +84,15 @@ abstract class AbstractElement */ protected $relationId; + /** + * Depth of table container nested level; Primarily used for RTF writer/reader + * + * 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc. + * + * @var int + */ + private $nestedLevel = 0; + /** * Get PhpWord * @@ -197,11 +206,31 @@ abstract class AbstractElement /** * Set relation Id * - * @param int $rId + * @param int $value */ - public function setRelationId($rId) + public function setRelationId($value) { - $this->relationId = $rId; + $this->relationId = $value; + } + + /** + * Get nested level + * + * @return int + */ + public function getNestedLevel() + { + return $this->nestedLevel; + } + + /** + * Set nested level + * + * @param int $value + */ + public function setNestedLevel($value) + { + $this->nestedLevel = $value; } /** diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 07957ac1..d7dcea34 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -71,6 +71,7 @@ class Row extends AbstractElement $cell = new Cell($width, $style); $cell->setDocPart($this->getDocPart(), $this->getDocPartId()); $cell->setPhpWord($this->phpWord); + $cell->setNestedLevel($this->getNestedLevel()); $this->cells[] = $cell; return $cell; diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 01d3d7c8..ace63460 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -45,7 +45,6 @@ class Table extends AbstractElement */ private $width = null; - /** * Create a new table * @@ -68,6 +67,7 @@ class Table extends AbstractElement $row = new Row($height, $style); $row->setDocPart($this->getDocPart(), $this->getDocPartId()); $row->setPhpWord($this->phpWord); + $row->setNestedLevel($this->getNestedLevel()); $this->rows[] = $row; return $row; @@ -109,16 +109,6 @@ class Table extends AbstractElement return $this->style; } - /** - * Set table width - * - * @param int $width - */ - public function setWidth($width) - { - $this->width = $width; - } - /** * Get table width * @@ -129,6 +119,16 @@ class Table extends AbstractElement return $this->width; } + /** + * Set table width + * + * @param int $width + */ + public function setWidth($width) + { + $this->width = $width; + } + /** * Get column count * From 2205377259731309383ccfa227bf2468730c25c4 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 31 May 2014 12:37:38 +0700 Subject: [PATCH 228/326] #245: Basic table support in RTF writer --- CHANGELOG.md | 1 + docs/elements.rst | 2 +- docs/intro.rst | 2 +- docs/src/documentation.md | 6 +- .../Writer/RTF/Element/AbstractElement.php | 1 + src/PhpWord/Writer/RTF/Element/Table.php | 142 ++++++++++++++++++ src/PhpWord/Writer/RTF/Element/TextBreak.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 25 ++- tests/PhpWord/Tests/Writer/ODTextTest.php | 2 +- .../PhpWord/Tests/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Tests/Writer/RTFTest.php | 2 +- 11 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 src/PhpWord/Writer/RTF/Element/Table.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 43b5373d..30d6f0a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Element: New `Line` element - @basjan GH-253 - Title: Ability to apply numbering in heading - @ivanlanin GH-193 - HTML Reader: Basic HTML reader - @ivanlanin GH-80 GH-254 +- RTF Writer: Basic table writing - @ivanlanin GH-245 ### Bugfixes diff --git a/docs/elements.rst b/docs/elements.rst index 98ab042f..7d076742 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -25,7 +25,7 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 8 | List | v | v | v | v | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ -| 9 | Table | v | v | v | ? | - | - | +| 9 | Table | v | v | v | v | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 10 | Image | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ diff --git a/docs/intro.rst b/docs/intro.rst index 94001237..aca5b241 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -81,7 +81,7 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | List | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Table | ✓ | ✓ | | ✓ | ✓ | +| | Table | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Image | ✓ | ✓ | ✓ | ✓ | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 773269a9..84522c1b 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -90,9 +90,9 @@ Below are the supported features for each file formats. | | Link | ✓ | ✓ | ✓ | ✓ | ✓ | | | Preserve Text | ✓ | | | | | | | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ | -| | Page Break | ✓ | | ✓ | | | +| | Page Break | ✓ | | ✓ | | | | | List | ✓ | | | | | -| | Table | ✓ | ✓ | | ✓ | ✓ | +| | Table | ✓ | ✓ | ✓ | ✓ | ✓ | | | Image | ✓ | ✓ | ✓ | ✓ | | | | Object | ✓ | | | | | | | Watermark | ✓ | | | | | @@ -454,7 +454,7 @@ Below are the matrix of element availability in each container. The column shows | 6 | Text Break | v | v | v | v | v | v | | 7 | Page Break | v | - | - | - | - | - | | 8 | List | v | v | v | v | - | - | -| 9 | Table | v | v | v | ? | - | - | +| 9 | Table | v | v | v | v | - | - | | 10 | Image | v | v | v | v | v | v | | 11 | Watermark | - | v | - | - | - | - | | 12 | Object | v | v | v | v | v | v | diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 7af93180..79e13947 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -98,6 +98,7 @@ abstract class AbstractElement extends HTMLAbstractElement } $styleWriter = new ParagraphStyleWriter($this->paragraphStyle); + $styleWriter->setNestedLevel($this->element->getNestedLevel()); return $styleWriter->write(); } diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php new file mode 100644 index 00000000..b48e084f --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -0,0 +1,142 @@ +element instanceof TableElement) { + return ''; + } + $element = $this->element; + // No nesting table for now + if ($element->getNestedLevel() >= 1) { + return ''; + } + + $content = ''; + $rows = $element->getRows(); + $rowCount = count($rows); + + if ($rowCount > 0) { + $content .= '\pard' . PHP_EOL; + + for ($i = 0; $i < $rowCount; $i++) { + $content .= '\trowd '; + $content .= $this->writeRowDef($rows[$i]); + $content .= PHP_EOL; + $content .= $this->writeRow($rows[$i]); + $content .= '\row' . PHP_EOL; + } + } + + return $content; + } + + /** + * Write column + * + * @return string + */ + private function writeRowDef(RowElement $row) + { + $content = ''; + + $rightMargin = 0; + foreach ($row->getCells() as $cell) { + $width = $cell->getWidth(); + $vMerge = $this->getVMerge($cell->getStyle()->getVMerge()); + if ($width === null) { + $width = 720; // Arbitrary default width + } + $rightMargin += $width; + $content .= "{$vMerge}\cellx{$rightMargin} "; + } + + return $content; + } + + /** + * Write row + * + * @return string + */ + private function writeRow(RowElement $row) + { + $content = ''; + + // Write cells + foreach ($row->getCells() as $cell) { + $content .= $this->writeCell($cell); + } + + return $content; + } + + /** + * Write cell + * + * @return string + */ + private function writeCell(CellElement $cell) + { + $content = '\intbl' . PHP_EOL; + + // Write content + $writer = new Container($this->parentWriter, $cell); + $content .= $writer->write(); + + $content .= '\cell' . PHP_EOL; + + return $content; + } + + /** + * Get vertical merge style + * + * @param string $value + * @return string + * @todo Move to style + */ + private function getVMerge($value) + { + $style = ''; + if ($value == 'restart') { + $style = '\clvmgf'; + } elseif ($value == 'continue') { + $style = '\clvmrg'; + } + + return $style; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 4449be65..57dc6349 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -35,6 +35,6 @@ class TextBreak extends AbstractElement $parentWriter = $this->parentWriter; $parentWriter->setLastParagraphStyle(); - return '\par' . PHP_EOL; + return '\pard\par' . PHP_EOL; } } diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index e5f5d85e..b166cc27 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -26,6 +26,16 @@ use PhpOffice\PhpWord\Style\Alignment; */ class Paragraph extends AbstractStyle { + + /** + * Depth of table container nested level; Primarily used for RTF writer/reader + * + * 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc. + * + * @var int + */ + private $nestedLevel = 0; + /** * Write style * @@ -49,7 +59,10 @@ class Paragraph extends AbstractStyle $spaceAfter = $style->getSpaceAfter(); $spaceBefore = $style->getSpaceBefore(); - $content = '\pard\nowidctlpar'; + $content = ''; + if ($this->nestedLevel == 0) { + $content .= '\pard\nowidctlpar '; + } if (isset($alignments[$align])) { $content .= $alignments[$align]; } @@ -58,4 +71,14 @@ class Paragraph extends AbstractStyle return $content; } + + /** + * Set nested level + * + * @param int $value + */ + public function setNestedLevel($value) + { + $this->nestedLevel = $value; + } } diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 88e673fb..25b8095b 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -79,7 +79,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); - $section->addTable(); + $section->addTable()->addRow()->addCell()->addText('Test'); $section->addListItem('Test'); $section->addImage($imageSrc); $section->addObject($objectSrc); diff --git a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php index a31117e6..e1e0e4a7 100644 --- a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php @@ -28,7 +28,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Text', 'Title', 'Link'); + $elements = array('Container', 'Text', 'Title', 'Link', 'Table'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $element; $parentWriter = new RTF(); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 51a66a7d..cc88a91a 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -68,7 +68,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); - $section->addTable(); + $section->addTable()->addRow()->addCell()->addText('Test'); $section->addListItem('Test'); $section->addImage($imageSrc); $section->addObject($objectSrc); From 9839222492ba1f2e17935ab78913fa33e0b0722b Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 31 May 2014 17:39:54 +0700 Subject: [PATCH 229/326] QA: Additional unit tests --- src/PhpWord/Element/AbstractContainer.php | 86 ++++++++++++------- src/PhpWord/Reader/ODText/AbstractPart.php | 2 +- src/PhpWord/Shared/XMLWriter.php | 3 + src/PhpWord/Shared/ZipArchive.php | 1 + src/PhpWord/Writer/AbstractWriter.php | 13 +++ src/PhpWord/Writer/HTML/Element/Text.php | 2 +- src/PhpWord/Writer/HTML/Style/Font.php | 2 +- src/PhpWord/Writer/ODText/Part/Meta.php | 11 ++- src/PhpWord/Writer/PDF/AbstractRenderer.php | 6 ++ tests/PhpWord/Tests/Element/FieldTest.php | 42 ++++++++- tests/PhpWord/Tests/Shared/XMLReaderTest.php | 13 +++ .../Tests/Style/NumberingLevelTest.php | 1 + tests/PhpWord/Tests/Style/ParagraphTest.php | 2 + .../PhpWord/Tests/Writer/HTML/ElementTest.php | 15 ++++ tests/PhpWord/Tests/Writer/HTML/PartTest.php | 36 ++++++++ tests/PhpWord/Tests/Writer/HTMLTest.php | 2 +- .../Tests/Writer/ODText/Part/ContentTest.php | 3 + .../PhpWord/Tests/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Tests/Writer/RTFTest.php | 11 ++- .../Tests/Writer/Word2007/ElementTest.php | 24 ++++++ .../Writer/Word2007/Part/DocumentTest.php | 2 + .../Tests/Writer/Word2007/StyleTest.php | 19 ++++ 22 files changed, 254 insertions(+), 44 deletions(-) create mode 100644 tests/PhpWord/Tests/Writer/HTML/PartTest.php diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 95186749..99927c68 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -60,49 +60,29 @@ abstract class AbstractContainer extends AbstractElement if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { $args[3] = null; // Remove paragraph style for texts in textrun } + $source = ''; + if (count($args) > 1) { + $source = $args[1]; + } // Create element using reflection $reflection = new \ReflectionClass($elementClass); $elementArgs = $args; - array_shift($elementArgs); // Shift an element off the beginning of array: the $elementName + array_shift($elementArgs); // Shift the $elementName off the beginning of array /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ $element = $reflection->newInstanceArgs($elementArgs); - // Set nested level - if ($this->container == 'Cell') { - $element->setNestedLevel($this->getNestedLevel() + 1); - } else { - $element->setNestedLevel($this->getNestedLevel()); - } - - - // Set relation Id for media collection - $mediaContainer = $this->getMediaContainer(); - if (in_array($elementName, array('Link', 'Image', 'Object'))) { - /** @var \PhpOffice\PhpWord\Element\Image $element Type hint */ - $image = ($elementName == 'Image') ? $element : null; - $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $image); - $element->setRelationId($rId); - } - if ($elementName == 'Object') { - /** @var \PhpOffice\PhpWord\Element\Object $element Type hint */ - $rIdIcon = Media::addElement($mediaContainer, 'image', $element->getIcon(), new Image($element->getIcon())); - $element->setImageRelationId($rIdIcon); - } - - // Set relation Id for other collection - if (in_array($elementName, array('Footnote', 'Endnote', 'Title')) && $this->phpWord instanceof PhpWord) { - $addMethod = "add{$elementName}"; - $rId = $this->phpWord->$addMethod($element); - $element->setRelationId($rId); - } + // Set nested level and relation Id + $this->setElementNestedLevel($element); + $this->setElementRelationId($element, $elementName, $source); // Set other properties and add element into collection $element->setDocPart($this->getDocPart(), $this->getDocPartId()); $element->setElementIndex($this->countElements() + 1); $element->setElementId(); $element->setPhpWord($this->phpWord); + $this->elements[] = $element; return $element; @@ -128,6 +108,54 @@ abstract class AbstractContainer extends AbstractElement return count($this->elements); } + /** + * Set element nested level based on container; add one when it's inside a cell + */ + private function setElementNestedLevel(AbstractElement $element) + { + if ($this->container == 'Cell') { + $element->setNestedLevel($this->getNestedLevel() + 1); + } else { + $element->setNestedLevel($this->getNestedLevel()); + } + } + + /** + * Set relation Id + * + * @param string $elementName + * @param string $source + */ + private function setElementRelationId(AbstractElement $element, $elementName, $source) + { + $mediaContainer = $this->getMediaContainer(); + $hasMediaRelation = in_array($elementName, array('Link', 'Image', 'Object')); + $hasOtherRelation = in_array($elementName, array('Footnote', 'Endnote', 'Title')); + + // Set relation Id for media elements (link, image, object; legacy of OOXML) + // Only Image that needs to be passed to Media class + if ($hasMediaRelation) { + /** @var \PhpOffice\PhpWord\Element\Image $element Type hint */ + $image = ($elementName == 'Image') ? $element : null; + $rId = Media::addElement($mediaContainer, strtolower($elementName), $source, $image); + $element->setRelationId($rId); + } + + // Set relation Id for icon of object element + if ($elementName == 'Object') { + /** @var \PhpOffice\PhpWord\Element\Object $element Type hint */ + $rIdIcon = Media::addElement($mediaContainer, 'image', $element->getIcon(), new Image($element->getIcon())); + $element->setImageRelationId($rIdIcon); + } + + // Set relation Id for elements that will be registered in the Collection subnamespaces + if ($hasOtherRelation && $this->phpWord instanceof PhpWord) { + $addMethod = "add{$elementName}"; + $rId = $this->phpWord->$addMethod($element); + $element->setRelationId($rId); + } + } + /** * Add text/preservetext element * diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 2097df9c..95f70084 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -23,7 +23,7 @@ use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart; * Abstract part reader * * @since 0.10.0 - * @codeCoverageIgnore Nothing in here yet + * @codeCoverageIgnore */ abstract class AbstractPart extends Word2007AbstractPart { diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 81e8e286..cb00c70b 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -69,9 +69,12 @@ class XMLWriter $this->tempFile = @tempnam($tempFolder, 'xml'); // Fallback to memory when temporary file cannot be used + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. if ($this->xmlWriter->openUri($this->tempFile) === false) { $this->xmlWriter->openMemory(); } + // @codeCoverageIgnoreEnd } // Set xml Compatibility diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index a5a37ec0..cbfcb071 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -152,6 +152,7 @@ class ZipArchive * * @return bool * @throws \PhpOffice\PhpWord\Exception\Exception + * @codeCoverageIgnore Can't find any test case. Uncomment when found. */ public function close() { diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 367b7729..346e9b66 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -219,9 +219,12 @@ abstract class AbstractWriter implements WriterInterface $this->originalFilename = $filename; if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { $filename = @tempnam(sys_get_temp_dir(), 'phpword_'); + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. if ($filename == '') { $filename = $this->originalFilename; } + // @codeCoverageIgnoreEnd } $this->tempFilename = $filename; @@ -234,9 +237,12 @@ abstract class AbstractWriter implements WriterInterface protected function cleanupTempFile() { if ($this->originalFilename != $this->tempFilename) { + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. if (copy($this->tempFilename, $this->originalFilename) === false) { throw new Exception("Could not copy temporary zip file."); } + // @codeCoverageIgnoreEnd @unlink($this->tempFilename); } @@ -269,11 +275,15 @@ abstract class AbstractWriter implements WriterInterface // Try opening the ZIP file $zip = new ZipArchive(); + + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. if ($zip->open($filename, ZipArchive::OVERWRITE) !== true) { if ($zip->open($filename, ZipArchive::CREATE) !== true) { throw new \Exception("Could not open '{$filename}' for writing."); } } + // @codeCoverageIgnoreEnd return $zip; } @@ -290,9 +300,12 @@ abstract class AbstractWriter implements WriterInterface { $filename = $this->getTempFile($filename); $fileHandle = fopen($filename, 'w'); + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. if ($fileHandle === false) { throw new \Exception("Could not open '{$filename}' for writing."); } + // @codeCoverageIgnoreEnd return $fileHandle; } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index cbabc645..52e7a6b5 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -70,6 +70,7 @@ class Text extends AbstractElement $content = ''; $content .= $this->writeOpening(); + $content .= $this->openingText; $content .= $this->openingTags; $content .= htmlspecialchars($element->getText()); $content .= $this->closingTags; @@ -113,7 +114,6 @@ class Text extends AbstractElement $style = $this->getParagraphStyle(); } $content .= ""; - $content .= $this->openingText; } return $content; diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index aec36bbb..18f28287 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -49,7 +49,7 @@ class Font extends AbstractStyle $css['font-family'] = $this->getValueIf($font !== null, "'{$font}'"); $css['font-size'] = $this->getValueIf($size !== null, "{$size}pt"); - $css['color'] = $this->getValueIf($color != Settings::DEFAULT_FONT_COLOR, "#{$color}"); + $css['color'] = $this->getValueIf($color !== null, "#{$color}"); $css['background'] = $this->getValueIf($fgColor != '', $fgColor); $css['font-weight'] = $this->getValueIf($style->isBold(), 'bold'); $css['font-style'] = $this->getValueIf($style->isItalic(), 'italic'); diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 0d240a68..c9e729ad 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -89,17 +89,16 @@ class Meta extends AbstractPart * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $property * @param string $value - * @param string $type string (default/null) * - * @todo Handle other `$type`: double|date|dateTime|duration|boolean + * @todo Handle other `$type`: double|date|dateTime|duration|boolean (4th arguments) */ - private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value, $type = null) + private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value) { $xmlWriter->startElement('meta:user-defined'); $xmlWriter->writeAttribute('meta:name', $property); - if ($type !== null) { - $xmlWriter->writeAttribute('meta:value-type', $type); - } + // if ($type !== null) { + // $xmlWriter->writeAttribute('meta:value-type', $type); + // } $xmlWriter->writeRaw($value); $xmlWriter->endElement(); // meta:user-defined } diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 83b02251..d4288c8a 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -87,7 +87,10 @@ abstract class AbstractRenderer extends HTML /** @noinspection PhpIncludeInspection Dynamic includes */ require_once $includeFile; } else { + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. throw new Exception('Unable to load PDF Rendering library'); + // @codeCoverageIgnoreEnd } } @@ -172,9 +175,12 @@ abstract class AbstractRenderer extends HTML protected function prepareForSave($filename = null) { $fileHandle = fopen($filename, 'w'); + // @codeCoverageIgnoreStart + // Can't find any test case. Uncomment when found. if ($fileHandle === false) { throw new Exception("Could not open file $filename for writing."); } + // @codeCoverageIgnoreEnd $this->isPdf = true; return $fileHandle; diff --git a/tests/PhpWord/Tests/Element/FieldTest.php b/tests/PhpWord/Tests/Element/FieldTest.php index 68fd8a84..2f9193d4 100644 --- a/tests/PhpWord/Tests/Element/FieldTest.php +++ b/tests/PhpWord/Tests/Element/FieldTest.php @@ -43,7 +43,7 @@ class FieldTest extends \PHPUnit_Framework_TestCase public function testConstructWithType() { $oField = new Field('DATE'); - + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); $this->assertEquals($oField->getType(), 'DATE'); } @@ -54,7 +54,7 @@ class FieldTest extends \PHPUnit_Framework_TestCase public function testConstructWithTypeProperties() { $oField = new Field('DATE', array('dateformat'=>'d-M-yyyy')); - + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); $this->assertEquals($oField->getType(), 'DATE'); $this->assertEquals($oField->getProperties(), array('dateformat'=>'d-M-yyyy')); @@ -66,10 +66,46 @@ class FieldTest extends \PHPUnit_Framework_TestCase public function testConstructWithTypePropertiesOptions() { $oField = new Field('DATE', array('dateformat'=>'d-M-yyyy'), array('SakaEraCalendar', 'PreserveFormat')); - + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); $this->assertEquals($oField->getType(), 'DATE'); $this->assertEquals($oField->getProperties(), array('dateformat'=>'d-M-yyyy')); $this->assertEquals($oField->getOptions(), array('SakaEraCalendar', 'PreserveFormat')); } + + /** + * Test setType exception + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid type + */ + public function testSetTypeException() + { + $object = new Field(); + $object->setType('foo'); + } + + /** + * Test setProperties exception + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid property + */ + public function testSetPropertiesException() + { + $object = new Field('PAGE'); + $object->setProperties(array('foo' => 'bar')); + } + + /** + * Test setOptions exception + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid option + */ + public function testSetOptionsException() + { + $object = new Field('PAGE'); + $object->setOptions(array('foo' => 'bar')); + } } diff --git a/tests/PhpWord/Tests/Shared/XMLReaderTest.php b/tests/PhpWord/Tests/Shared/XMLReaderTest.php index 5c5da682..2bb6ef65 100644 --- a/tests/PhpWord/Tests/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Tests/Shared/XMLReaderTest.php @@ -27,6 +27,19 @@ use PhpOffice\PhpWord\Shared\XMLReader; */ class XMLReaderTest extends \PHPUnit_Framework_TestCase { + /** + * Test get DOMDocument from ZipArchive exception + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage Cannot find archive file. + */ + public function testGetDomFromZipException() + { + $filename = __DIR__ . "/../_files/documents/foo.zip"; + $object = new XMLReader(); + $object->getDomFromZip($filename, 'yadayadaya'); + } + /** * Test get DOMDocument from ZipArchive returns false */ diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Tests/Style/NumberingLevelTest.php index c0cfa297..8959a983 100644 --- a/tests/PhpWord/Tests/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Tests/Style/NumberingLevelTest.php @@ -38,6 +38,7 @@ class NumberingLevelTest extends \PHPUnit_Framework_TestCase 'start' => 1, 'format' => 'decimal', 'restart' => 1, + 'pStyle' => 'pStyle', 'suffix' => 'space', 'text' => '%1.', 'align' => 'left', diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 32e46985..12aa51ce 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -75,6 +75,8 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase 'spacing' => 120, 'basedOn' => 'Normal', 'next' => 'Normal', + 'numStyle' => 'numStyle', + 'numLevel' => 1, 'widowControl' => false, 'keepNext' => true, 'keepLines' => true, diff --git a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php b/tests/PhpWord/Tests/Writer/HTML/ElementTest.php index e12193e8..ae136d34 100644 --- a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/HTML/ElementTest.php @@ -16,7 +16,9 @@ */ namespace PhpOffice\PhpWord\Tests\Writer\HTML; +use PhpOffice\PhpWord\Element\Text as TextElement; use PhpOffice\PhpWord\Writer\HTML; +use PhpOffice\PhpWord\Writer\HTML\Element\Text; /** * Test class for PhpOffice\PhpWord\Writer\HTML\Element subnamespace @@ -38,4 +40,17 @@ class ElementTest extends \PHPUnit_Framework_TestCase $this->assertEquals('', $object->write()); } } + + /** + * Test write element text + */ + public function testWriteTextElement() + { + $object = new Text(new HTML(), new TextElement('A')); + $object->setOpeningText('-'); + $object->setClosingText('-'); + $object->setWithoutP(true); + + $this->assertEquals('-A-', $object->write()); + } } diff --git a/tests/PhpWord/Tests/Writer/HTML/PartTest.php b/tests/PhpWord/Tests/Writer/HTML/PartTest.php new file mode 100644 index 00000000..93e9a98e --- /dev/null +++ b/tests/PhpWord/Tests/Writer/HTML/PartTest.php @@ -0,0 +1,36 @@ +getParentWriter(); + } +} diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index 0a59b3df..f9b8e6ba 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -67,7 +67,7 @@ class HTMLTest extends \PHPUnit_Framework_TestCase $phpWord->addTitleStyle(1, array('bold' => true)); $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $phpWord->addParagraphStyle('Paragraph', array('align' => 'center', 'spaceAfter' => 20, 'spaceBefore' => 20)); $section = $phpWord->addSection(); $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index f75946cc..27b2427f 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -47,6 +47,9 @@ class ContentTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); + $docProps = $phpWord->getDocumentProperties(); + $docProps->setCustomProperty('Company', 'PHPWord'); + $phpWord->setDefaultFontName('Verdana'); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); diff --git a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php index e1e0e4a7..e090b349 100644 --- a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php @@ -28,7 +28,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Text', 'Title', 'Link', 'Table'); + $elements = array('Container', 'Text', 'Title', 'Link', 'Image', 'Table'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $element; $parentWriter = new RTF(); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index cc88a91a..c1448106 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -68,7 +68,16 @@ class RTFTest extends \PHPUnit_Framework_TestCase $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); - $section->addTable()->addRow()->addCell()->addText('Test'); + + // Rowspan + $table = $section->addTable(); + $table->addRow()->addCell(null, array('vMerge' => 'restart'))->addText('Test'); + $table->addRow()->addCell(null, array('vMerge' => 'continue'))->addText('Test'); + + // Nested table + $cell = $section->addTable()->addRow()->addCell(); + $cell->addTable()->addRow()->addCell(); + $section->addListItem('Test'); $section->addImage($imageSrc); $section->addObject($objectSrc); diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 23ba575b..da7504b5 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -16,13 +16,23 @@ */ namespace PhpOffice\PhpWord\Tests\Writer\Word2007; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace */ class ElementTest extends \PHPUnit_Framework_TestCase { + /** + * Executed before each method of the class + */ + public function tearDown() + { + TestHelperDOCX::clear(); + } + /** * Test unmatched element */ @@ -43,4 +53,18 @@ class ElementTest extends \PHPUnit_Framework_TestCase $this->assertEquals('', $xmlWriter->getData()); } } + + /** + * Test line element + */ + public function testLineElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addLine(array('width' => 1000, 'height' => 1000, 'positioning' => 'absolute', 'flip' => true)); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = "/w:document/w:body/w:p/w:r/w:pict/v:shapetype"; + $this->assertTrue($doc->elementExists($element)); + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index e3933557..7ff4cb7c 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -43,6 +43,8 @@ class DocumentTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $section = $phpWord->addSection(); + $section->addHeader(); + $section->addHeader('first'); $settings = $section->getSettings(); $settings->setLandscape(); $settings->setPageNumberingStart(2); diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php index 8303e92b..71cbc300 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php @@ -42,4 +42,23 @@ class StyleTest extends \PHPUnit_Framework_TestCase $this->assertEquals('', $xmlWriter->getData()); } } + + /** + * Test method exceptions + */ + public function testMethodExceptions() + { + $styles = array( + 'Image' => 'writeAlignment', + 'Line' => 'writeStroke', + ); + foreach ($styles as $style => $method) { + $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style; + $xmlWriter = new XMLWriter(); + $object = new $objectClass($xmlWriter); + $object->$method(); + + $this->assertEquals('', $xmlWriter->getData()); + } + } } From e0d2c6584c55913f5f18d972025883db94f350ee Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 1 Jun 2014 00:12:35 +0700 Subject: [PATCH 230/326] Refactor IOFactory and AbstractContainer to allow more dynamic inclusion. --- src/PhpWord/Element/AbstractContainer.php | 267 +++++------------- src/PhpWord/IOFactory.php | 32 ++- .../Writer/Word2007/Part/DocumentTest.php | 6 +- 3 files changed, 90 insertions(+), 215 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 99927c68..4bbe5ddf 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -23,6 +23,23 @@ use PhpOffice\PhpWord\PhpWord; /** * Container abstract class * + * @method Text addText($text, $fStyle = null, $pStyle = null) + * @method TextRun addTextRun($pStyle = null) + * @method Link addLink($target, $text = null, $fStyle = null, $pStyle = null) + * @method PreserveText addPreserveText($text, $fStyle = null, $pStyle = null) + * @method void addTextBreak($count = 1, $fStyle = null, $pStyle = null) + * @method ListItem addListItem($text, $depth = 0, $fStyle = null, $listStyle = null, $pStyle = null) + * @method ListItemRun addListItemRun($depth = 0, $listStyle = null, $pStyle = null) + * @method Table addTable($style = null) + * @method Image addImage($source, $style = null, $isWatermark = false) + * @method Object addObject($source, $style = null) + * @method Footnote addFootnote($pStyle = null) + * @method Endnote addEndnote($pStyle = null) + * @method CheckBox addCheckBox($name, $text, $fStyle = null, $pStyle = null) + * @method TextBox addTextBox($style = null) + * @method Field addField($type = null, $properties = array(), $options = array()) + * @method Line addLine($lineStyle = null) + * * @since 0.10.0 */ abstract class AbstractContainer extends AbstractElement @@ -41,6 +58,53 @@ abstract class AbstractContainer extends AbstractElement */ protected $container; + /** + * Magic method to catch all 'addElement' variation + * + * This removes addText, addTextRun, etc. When adding new element, we have to + * add the model in the class docblock with `@method`. + * + * Warning: This makes capitalization matters, e.g. addCheckbox or addcheckbox won't work. + * + * @param mixed $function + * @param mixed $args + * @return \PhpOffice\PhpWord\Element\AbstractElement + */ + public function __call($function, $args) + { + $elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', + 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', + 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line'); + $functions = array(); + for ($i = 0; $i < count($elements); $i++) { + $functions[$i] = 'add' . $elements[$i]; + } + + // Run valid `add` command + if (in_array($function, $functions)) { + $element = str_replace('add', '', $function); + + // Special case for TextBreak + // @todo Remove the `$count` parameter in 1.0.0 to make this element similiar to other elements? + if ($element == 'TextBreak') { + @list($count, $fontStyle, $paragraphStyle) = $args; // Suppress error + if ($count === null) { + $count = 1; + } + for ($i = 1; $i <= $count; $i++) { + $this->addElement($element, $fontStyle, $paragraphStyle); + } + + // All other elements + } else { + array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); + } + } + + return null; + } + /** * Add element * @@ -156,209 +220,6 @@ abstract class AbstractContainer extends AbstractElement } } - /** - * Add text/preservetext element - * - * @param string $text - * @param mixed $fontStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\PreserveText - */ - public function addText($text, $fontStyle = null, $paragraphStyle = null) - { - return $this->addElement('Text', $text, $fontStyle, $paragraphStyle); - } - - /** - * Add textrun element - * - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\TextRun - */ - public function addTextRun($paragraphStyle = null) - { - return $this->addElement('TextRun', $paragraphStyle); - } - - /** - * Add link element - * - * @param string $target - * @param string $text - * @param mixed $fontStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\Link - */ - public function addLink($target, $text = null, $fontStyle = null, $paragraphStyle = null) - { - return $this->addElement('Link', $target, $text, $fontStyle, $paragraphStyle); - } - - /** - * Add preserve text element - * - * @param string $text - * @param mixed $fontStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\PreserveText - */ - public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) - { - return $this->addElement('PreserveText', $text, $fontStyle, $paragraphStyle); - } - - /** - * Add text break element - * - * @param int $count - * @param mixed $fontStyle - * @param mixed $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->addElement('TextBreak', $fontStyle, $paragraphStyle); - } - } - - /** - * Add listitem element - * - * @param string $text - * @param int $depth - * @param mixed $fontStyle - * @param mixed $listStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\ListItem - */ - public function addListItem($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) - { - return $this->addElement('ListItem', $text, $depth, $fontStyle, $listStyle, $paragraphStyle); - } - - /** - * Add listitemrun element - * - * @param int $depth - * @param mixed $listStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\ListItemRun - */ - public function addListItemRun($depth = 0, $listStyle = null, $paragraphStyle = null) - { - return $this->addElement('ListItemRun', $depth, $listStyle, $paragraphStyle); - } - - /** - * Add table element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Table - */ - public function addTable($style = null) - { - return $this->addElement('Table', $style); - } - - /** - * Add image element - * - * @param string $source - * @param mixed $style Image style - * @param bool $isWatermark - * @return \PhpOffice\PhpWord\Element\Image - */ - public function addImage($source, $style = null, $isWatermark = false) - { - return $this->addElement('Image', $source, $style, $isWatermark); - } - - /** - * Add OLE-object element - * - * All exceptions should be handled by \PhpOffice\PhpWord\Element\Object - * - * @param string $source - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Object - */ - public function addObject($source, $style = null) - { - return $this->addElement('Object', $source, $style); - } - - /** - * Add footnote element - * - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\Footnote - */ - public function addFootnote($paragraphStyle = null) - { - return $this->addElement('Footnote', $paragraphStyle); - } - - /** - * Add endnote element - * - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\Endnote - */ - public function addEndnote($paragraphStyle = null) - { - return $this->addElement('Endnote', $paragraphStyle); - } - - /** - * Add a CheckBox Element - * - * @param string $name - * @param string $text - * @param mixed $fontStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Element\CheckBox - */ - public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) - { - return $this->addElement('CheckBox', $name, $text, $fontStyle, $paragraphStyle); - } - - /** - * Add textbox element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\TextBox - */ - public function addTextBox($style = null) - { - return $this->addElement('TextBox', $style); - } - - /** - * Add field element - * - * @param string $type - * @param array $properties - * @param array $options - * @return \PhpOffice\PhpWord\Element\Field - */ - public function addField($type = null, $properties = array(), $options = array()) - { - return $this->addElement('Field', $type, $properties, $options); - } - - /** - * Add line element - * - * @param mixed $lineStyle - * @return \PhpOffice\PhpWord\Element\Line - */ - public function addLine($lineStyle = null) - { - return $this->addElement('Line', $lineStyle); - - } - /** * Check if a method is allowed for the current container * diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 1d784962..166ea152 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -20,7 +20,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\Exception; /** - * IO factory + * IO Factory */ abstract class IOFactory { @@ -34,12 +34,12 @@ abstract class IOFactory */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML', 'PDF'))) { + $class = 'PhpOffice\\PhpWord\\Writer\\' . $name; + if (class_exists($class) && self::isConcreteClass($class)) { + return new $class($phpWord); + } else { throw new Exception("\"{$name}\" is not a valid writer."); } - - $fqName = "PhpOffice\\PhpWord\\Writer\\{$name}"; - return new $fqName($phpWord); } /** @@ -51,12 +51,12 @@ abstract class IOFactory */ public static function createReader($name = 'Word2007') { - if (!in_array($name, array('ReaderInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) { + $class = 'PhpOffice\\PhpWord\\Reader\\' . $name; + if (class_exists($class) && self::isConcreteClass($class)) { + return new $class(); + } else { throw new Exception("\"{$name}\" is not a valid reader."); } - - $fqName = "PhpOffice\\PhpWord\\Reader\\{$name}"; - return new $fqName(); } /** @@ -69,6 +69,20 @@ abstract class IOFactory public static function load($filename, $readerName = 'Word2007') { $reader = self::createReader($readerName); + return $reader->load($filename); } + + /** + * Check if it's a concrete class (not abstract nor interface) + * + * @param string $class + * @return bool + */ + private static function isConcreteClass($class) + { + $reflection = new \ReflectionClass($class); + + return !$reflection->isAbstract() && !$reflection->isInterface(); + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 7ff4cb7c..e27d072a 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -355,10 +355,10 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $pStyle = 'pStyle'; $phpWord = new PhpWord(); - $phpWord->addFontStyle($rStyle, array('bold' => true)); - $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); + // $phpWord->addFontStyle($rStyle, array('bold' => true)); + // $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); $section = $phpWord->addSection(); - $section->addCheckbox('Check1', 'Test', $rStyle, $pStyle); + $section->addCheckBox('Check1', 'Test', $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:r/w:fldChar/w:ffData/w:name'; From ce21e8d9e8013389f0abb6b9bf78879c058b6319 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 1 Jun 2014 21:00:02 +0700 Subject: [PATCH 231/326] PR 0.11.0 #225 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d6f0a3..cd4d6f34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,9 @@ This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. -## 0.11.0 - Not yet released +## 0.11.0 - 1 June 2014 -This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF and HTML reader were initiated. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemented. RTF and HTML reader were initiated. ### Features From 4dd85e28c66fe218f585b8e8af75ab5a6cdea96d Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 1 Jun 2014 22:32:20 +0700 Subject: [PATCH 232/326] Version and changelog for 0.12.0 --- CHANGELOG.md | 18 ++++++++++++++++++ VERSION | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd4d6f34..c6f0e3b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. +## 0.12.0 - Not yet released + +### Features + +None yet. + +### Bugfixes + +None yet. + +### Deprecated + +None yet. + +### Miscellaneous + +None yet. + ## 0.11.0 - 1 June 2014 This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemented. RTF and HTML reader were initiated. diff --git a/VERSION b/VERSION index 142464bf..d33c3a21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.0 \ No newline at end of file +0.12.0 \ No newline at end of file From 38d3d7be20e6eb8d5f56e77515a49ceb41b676b6 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 2 Jun 2014 18:27:23 +0700 Subject: [PATCH 233/326] Bugfix for #257: HTML Reader: `

    ` and header tags puts no output --- CHANGELOG.md | 6 ++++++ VERSION | 2 +- src/PhpWord/Shared/Html.php | 7 +++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd4d6f34..59cbba6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. +## 0.11.1 - 2 June 2014 + +This is an immediate bugfix release for HTML reader. + +- HTML Reader: `

    ` and header tags puts no output - @canyildiz @ivanlanin GH-257 + ## 0.11.0 - 1 June 2014 This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemented. RTF and HTML reader were initiated. diff --git a/VERSION b/VERSION index 142464bf..027934ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.0 \ No newline at end of file +0.11.1 \ No newline at end of file diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 83292a3a..8abfea2f 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -224,9 +224,12 @@ class Html private static function parseText($node, $element, &$styles) { $styles['font'] = self::parseInlineStyle($node, $styles['font']); - if (method_exists($element, 'addText')) { + + // Commented as source of bug #257. `method_exists` doesn't seems to work properly in this case. + // @todo Find better error checking for this one + // if (method_exists($element, 'addText')) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); - } + // } return null; } From a66f93ccdc78275928d36a412426eee2c48de865 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 2 Jun 2014 21:21:34 +0700 Subject: [PATCH 234/326] #123: New drawing shapes (arc, curve, line, polyline, rect, oval) --- CHANGELOG.md | 2 +- docs/elements.rst | 9 +- docs/intro.rst | 4 +- docs/src/documentation.md | 10 +- phpmd.xml.dist | 2 +- samples/Sample_31_Shape.php | 82 ++++++ src/PhpWord/Element/AbstractContainer.php | 4 +- src/PhpWord/Element/AbstractElement.php | 21 ++ src/PhpWord/Element/Shape.php | 88 ++++++ src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Extrusion.php | 106 ++++++++ src/PhpWord/Style/Fill.php | 69 +++++ src/PhpWord/Style/Frame.php | 159 +++++++++++ src/PhpWord/Style/Outline.php | 248 +++++++++++++++++ src/PhpWord/Style/Shadow.php | 97 +++++++ src/PhpWord/Style/Shape.php | 255 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/Shape.php | 169 ++++++++++++ .../Writer/Word2007/Style/AbstractStyle.php | 36 +++ .../Writer/Word2007/Style/Extrusion.php | 44 +++ src/PhpWord/Writer/Word2007/Style/Fill.php | 41 +++ src/PhpWord/Writer/Word2007/Style/Frame.php | 56 ++++ src/PhpWord/Writer/Word2007/Style/Image.php | 18 -- src/PhpWord/Writer/Word2007/Style/Outline.php | 48 ++++ .../Writer/Word2007/Style/Paragraph.php | 18 -- src/PhpWord/Writer/Word2007/Style/Shadow.php | 44 +++ src/PhpWord/Writer/Word2007/Style/Shape.php | 45 ++++ .../Tests/Writer/Word2007/ElementTest.php | 83 +++++- .../Tests/Writer/Word2007/StyleTest.php | 2 +- 28 files changed, 1715 insertions(+), 47 deletions(-) create mode 100644 samples/Sample_31_Shape.php create mode 100644 src/PhpWord/Element/Shape.php create mode 100644 src/PhpWord/Style/Extrusion.php create mode 100644 src/PhpWord/Style/Fill.php create mode 100644 src/PhpWord/Style/Frame.php create mode 100644 src/PhpWord/Style/Outline.php create mode 100644 src/PhpWord/Style/Shadow.php create mode 100644 src/PhpWord/Style/Shape.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Shape.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Extrusion.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Fill.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Frame.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Outline.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Shadow.php create mode 100644 src/PhpWord/Writer/Word2007/Style/Shape.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d6df064a..36c27c26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Features -None yet. +- Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin GH-123 ### Bugfixes diff --git a/docs/elements.rst b/docs/elements.rst index 7d076742..a3a81717 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -47,6 +47,8 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 19 | Line | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 20 | Shapes | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -490,7 +492,12 @@ Fields To be completed -Line +Lines +----- + +To be completed + +Shapes ------ To be completed diff --git a/docs/intro.rst b/docs/intro.rst index aca5b241..5045d4dc 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -99,11 +99,11 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Endnote | ✓ | | | ✓ | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| **Graphs** | 2D basic graphs | | | | | | +| **Graphs** | 2D basic graphs | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | 2D advanced graphs | | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | 3D graphs | | | | | | +| | 3D graphs | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | **Math** | OMML support | | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 84522c1b..e9716401 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -36,6 +36,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [Textboxes](#textboxes) - [Fields](#fields) - [Lines](#lines) + - [Shapes](#shapes) - [Templates](#templates) - [Writers & readers](#writers-readers) - [OOXML](#ooxml) @@ -101,9 +102,9 @@ Below are the supported features for each file formats. | | Footer | ✓ | | | | | | | Footnote | ✓ | | | ✓ | | | | Endnote | ✓ | | | ✓ | | -| **Graphs** | 2D basic graphs | | | | | | +| **Graphs** | 2D basic graphs | ✓ | | | | | | | 2D advanced graphs | | | | | | -| | 3D graphs | | | | | | +| | 3D graphs | ✓ | | | | | | **Math** | OMML support | | | | | | | | MathML support | | | | | | | **Bonus** | Encryption | | | | | | @@ -465,6 +466,7 @@ Below are the matrix of element availability in each container. The column shows | 17 | TextBox | v | v | v | v | - | - | | 18 | Field | v | v | v | v | v | v | | 19 | Line | v | v | v | v | v | v | +| 20 | Shape | v | v | v | v | v | v | Legend: @@ -850,6 +852,10 @@ To be completed. To be completed. +## Shapes + +To be completed. + # Templates You can create a docx template with included search-patterns that can be replaced by any value you wish. Only single-line values can be replaced. To load a template file, use the `loadTemplate` method. After loading the docx template, you can use the `setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. It is not possible to add new PHPWord elements to a loaded template file. diff --git a/phpmd.xml.dist b/phpmd.xml.dist index f0b62b2d..5eb348ec 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -18,7 +18,7 @@ - + diff --git a/samples/Sample_31_Shape.php b/samples/Sample_31_Shape.php new file mode 100644 index 00000000..02399992 --- /dev/null +++ b/samples/Sample_31_Shape.php @@ -0,0 +1,82 @@ +addTitleStyle(1, array('size' => 14, 'bold' => true)); + +$section = $phpWord->addSection(); + +// Arc +$section->addTitle('Arc', 1); +$section->addShape( + 'arc', + array( + 'points' => '-90 20', + 'frame' => array('width' => 120, 'height' => 120), + 'outline' => array('color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'), + ) +); + +// Curve +$section->addTitle('Curve', 1); +$section->addShape( + 'curve', + array( + 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow', + 'outline' => array('color' => '#66cc00', 'weight' => 2, 'dash' => 'dash', 'startArrow' => 'diamond', 'endArrow' => 'block'), + ) +); + +// Line +$section->addTitle('Line', 1); +$section->addShape( + 'line', + array( + 'points' => '1,1 150,30', + 'outline' => array('color' => '#cc00ff', 'line' => 'thickThin', 'weight' => 3, 'startArrow' => 'oval', 'endArrow' => 'classic'), + ) +); + +// Polyline +$section->addTitle('Polyline', 1); +$section->addShape( + 'polyline', + array( + 'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50', + 'outline' => array('color' => '#cc6666', 'weight' => 2, 'startArrow' => 'none', 'endArrow' => 'classic'), + ) +); + +// Rectangle +$section->addTitle('Rectangle', 1); +$section->addShape( + 'rect', + array( + 'roundness' => 0.2, + 'frame' => array('width' => 100, 'height' => 100, 'left' => 1, 'top' => 1), + 'fill' => array('color' => '#FFCC33'), + 'outline' => array('color' => '#990000', 'weight' => 1), + 'shadow' => array(), + ) +); + +// Oval +$section->addTitle('Oval', 1); +$section->addShape( + 'oval', + array( + 'frame' => array('width' => 100, 'height' => 70, 'left' => 1, 'top' => 1), + 'fill' => array('color' => '#33CC99'), + 'outline' => array('color' => '#333333', 'weight' => 2), + 'extrusion' => array(), + ) +); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 4bbe5ddf..ae750de9 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -39,6 +39,7 @@ use PhpOffice\PhpWord\PhpWord; * @method TextBox addTextBox($style = null) * @method Field addField($type = null, $properties = array(), $options = array()) * @method Line addLine($lineStyle = null) + * @method Shape addObject($type, $style = null) * * @since 0.10.0 */ @@ -74,7 +75,7 @@ abstract class AbstractContainer extends AbstractElement { $elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', - 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line'); + 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape'); $functions = array(); for ($i = 0; $i < count($elements); $i++) { $functions[$i] = 'add' . $elements[$i]; @@ -242,6 +243,7 @@ abstract class AbstractContainer extends AbstractElement 'Object' => $allContainers, 'Field' => $allContainers, 'Line' => $allContainers, + 'Shape' => $allContainers, 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index ca45ef23..c8e574b7 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -262,4 +262,25 @@ abstract class AbstractElement return $style; } + + /** + * Set enum value + * + * @param mixed $value + * @param array $enum + * @param mixed $default + * @return mixed + * @throws \InvalidArgumentException + * @todo Merge with the same method in AbstractStyle + */ + protected function setEnumVal($value = null, $enum = array(), $default = null) + { + if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) { + throw new \InvalidArgumentException("Invalid style value: {$value}"); + } elseif ($value === null || trim($value) == '') { + $value = $default; + } + + return $value; + } } diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php new file mode 100644 index 00000000..9b3aae4f --- /dev/null +++ b/src/PhpWord/Element/Shape.php @@ -0,0 +1,88 @@ +setType($type); + $this->style = $this->setStyle(new ShapeStyle(), $style); + } + + /** + * Get type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set pattern + * + * @param string $value + * @return self + */ + public function setType($value = null) + { + $enum = array('arc', 'curve', 'line', 'polyline', 'rect', 'oval'); + $this->type = $this->setEnumVal($value, $enum, null); + + return $this; + } + + /** + * Get shape style + * + * @return \PhpOffice\PhpWord\Style\Shape + */ + public function getStyle() + { + return $this->style; + } +} diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 13ef8f9b..4d375888 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -264,7 +264,7 @@ abstract class AbstractStyle protected function setEnumVal($value = null, $enum = array(), $default = null) { if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) { - throw new \InvalidArgumentException('Invalid style value.'); + throw new \InvalidArgumentException("Invalid style value: {$value}"); } elseif ($value === null || trim($value) == '') { $value = $default; } diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php new file mode 100644 index 00000000..ccbb2650 --- /dev/null +++ b/src/PhpWord/Style/Extrusion.php @@ -0,0 +1,106 @@ +setStyleByArray($style); + } + + /** + * Get type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set pattern + * + * @param string $value + * @return self + */ + public function setType($value = null) + { + $enum = array(self::EXTRUSION_PARALLEL, self::EXTRUSION_PERSPECTIVE); + $this->type = $this->setEnumVal($value, $enum, null); + + return $this; + } + + /** + * Get color + * + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * Set color + * + * @param string $value + * @return self + */ + public function setColor($value = null) + { + $this->color = $value; + + return $this; + } +} diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php new file mode 100644 index 00000000..08c7a857 --- /dev/null +++ b/src/PhpWord/Style/Fill.php @@ -0,0 +1,69 @@ +setStyleByArray($style); + } + + /** + * Get color + * + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * Set color + * + * @param string $value + * @return self + */ + public function setColor($value = null) + { + $this->color = $value; + + return $this; + } +} diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php new file mode 100644 index 00000000..fce3f4a9 --- /dev/null +++ b/src/PhpWord/Style/Frame.php @@ -0,0 +1,159 @@ +setStyleByArray($style); + } + + /** + * Get width + * + * @return int|float + */ + public function getWidth() + { + return $this->width; + } + + /** + * Set width + * + * @param int|float $value + * @return self + */ + public function setWidth($value = null) + { + $this->width = $this->setNumericVal($value, null); + + return $this; + } + + /** + * Get height + * + * @return int|float + */ + public function getHeight() + { + return $this->height; + } + + /** + * Set height + * + * @param int|float $value + * @return self + */ + public function setHeight($value = null) + { + $this->height = $this->setNumericVal($value, null); + + return $this; + } + + /** + * Get left + * + * @return int|float + */ + public function getLeft() + { + return $this->left; + } + + /** + * Set left + * + * @param int|float $value + * @return self + */ + public function setLeft($value = 0) + { + $this->left = $this->setNumericVal($value, 0); + + return $this; + } + + /** + * Get topmost position + * + * @return int|float + */ + public function getTop() + { + return $this->top; + } + + /** + * Set topmost position + * + * @param int|float $value + * @return self + */ + public function setTop($value = 0) + { + $this->top = $this->setNumericVal($value, 0); + + return $this; + } +} diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php new file mode 100644 index 00000000..7e6b19cf --- /dev/null +++ b/src/PhpWord/Style/Outline.php @@ -0,0 +1,248 @@ +setStyleByArray($style); + } + + /** + * Get weight + * + * @return int|float + */ + public function getWeight() + { + return $this->weight; + } + + /** + * Set weight + * + * @param int|float $value + * @return self + */ + public function setWeight($value = null) + { + $this->weight = $this->setNumericVal($value, null); + + return $this; + } + + /** + * Get color + * + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * Set color + * + * @param string $value + * @return self + */ + public function setColor($value = null) + { + $this->color = $value; + + return $this; + } + + /** + * Get dash type + * + * @return string + */ + public function getDash() + { + return $this->dash; + } + + /** + * Set dash type + * + * @param string $value + * @return self + */ + public function setDash($value = null) + { + $this->dash = $value; + + return $this; + } + + /** + * Get line style + * + * @return string + */ + public function getLine() + { + return $this->line; + } + + /** + * Set line style + * + * @param string $value + * @return self + */ + public function setLine($value = null) + { + $enum = array(self::LINE_SINGLE, self::LINE_THIN_THIN, self::LINE_THIN_THICK, + self::LINE_THICK_THIN, self::LINE_THICK_BETWEEN_THIN); + $this->line = $this->setEnumVal($value, $enum, null); + + return $this; + } + + /** + * Get startArrow + * + * @return string + */ + public function getStartArrow() + { + return $this->startArrow; + } + + /** + * Set pattern + * + * @param string $value + * @return self + */ + public function setStartArrow($value = null) + { + $enum = array(self::ARROW_NONE, self::ARROW_BLOCK, self::ARROW_CLASSIC, + self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN); + $this->startArrow = $this->setEnumVal($value, $enum, null); + + return $this; + } + + /** + * Get endArrow + * + * @return string + */ + public function getEndArrow() + { + return $this->endArrow; + } + + /** + * Set pattern + * + * @param string $value + * @return self + */ + public function setEndArrow($value = null) + { + $enum = array(self::ARROW_NONE, self::ARROW_BLOCK, self::ARROW_CLASSIC, + self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN); + $this->endArrow = $this->setEnumVal($value, $enum, null); + + return $this; + } +} diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php new file mode 100644 index 00000000..deafbff0 --- /dev/null +++ b/src/PhpWord/Style/Shadow.php @@ -0,0 +1,97 @@ +setStyleByArray($style); + } + + /** + * Get color + * + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * Set color + * + * @param string $value + * @return self + */ + public function setColor($value = null) + { + $this->color = $value; + + return $this; + } + + /** + * Get offset + * + * @return string + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Set offset + * + * @param string $value + * @return self + */ + public function setOffset($value = null) + { + $this->offset = $value; + + return $this; + } +} diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php new file mode 100644 index 00000000..c9809920 --- /dev/null +++ b/src/PhpWord/Style/Shape.php @@ -0,0 +1,255 @@ +setStyleByArray($style); + } + + /** + * Get points + * + * @return string + */ + public function getPoints() + { + return $this->points; + } + + /** + * Set points + * + * @param string $value + * @return self + */ + public function setPoints($value = null) + { + $this->points = $value; + + return $this; + } + + /** + * Get roundness + * + * @return int|float + */ + public function getRoundness() + { + return $this->roundness; + } + + /** + * Set roundness + * + * @param int|float $value + * @return self + */ + public function setRoundness($value = null) + { + $this->roundness = $this->setNumericVal($value, null); + + return $this; + } + + /** + * Get frame + * + * @return \PhpOffice\PhpWord\Style\Frame + */ + public function getFrame() + { + return $this->frame; + } + + /** + * Set frame + * + * @param mixed $value + * @return self + */ + public function setFrame($value = null) + { + $this->setObjectVal($value, 'Frame', $this->frame); + + return $this; + } + + /** + * Get fill + * + * @return \PhpOffice\PhpWord\Style\Fill + */ + public function getFill() + { + return $this->fill; + } + + /** + * Set fill + * + * @param mixed $value + * @return self + */ + public function setFill($value = null) + { + $this->setObjectVal($value, 'Fill', $this->fill); + + return $this; + } + + /** + * Get outline + * + * @return \PhpOffice\PhpWord\Style\Outline + */ + public function getOutline() + { + return $this->outline; + } + + /** + * Set outline + * + * @param mixed $value + * @return self + */ + public function setOutline($value = null) + { + $this->setObjectVal($value, 'Outline', $this->outline); + + return $this; + } + + /** + * Get shadow + * + * @return \PhpOffice\PhpWord\Style\Shadow + */ + public function getShadow() + { + return $this->shadow; + } + + /** + * Set shadow + * + * @param mixed $value + * @return self + */ + public function setShadow($value = null) + { + $this->setObjectVal($value, 'Shadow', $this->shadow); + + return $this; + } + + /** + * Get 3D extrusion + * + * @return \PhpOffice\PhpWord\Style\Extrusion + */ + public function getExtrusion() + { + return $this->extrusion; + } + + /** + * Set 3D extrusion + * + * @param mixed $value + * @return self + */ + public function setExtrusion($value = null) + { + $this->setObjectVal($value, 'Extrusion', $this->extrusion); + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php new file mode 100644 index 00000000..f4ac2efb --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -0,0 +1,169 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof ShapeElement) { + return; + } + + $style = $element->getStyle(); + $type = $element->getType(); + if ($type == 'rect' && $style->getRoundness() !== null) { + $type = 'roundrect'; + } + $method = "write{$type}"; + + if (!$this->withoutP) { + $xmlWriter->startElement('w:p'); + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:pict'); + $xmlWriter->startElement("v:{$type}"); + + // Element style + if (method_exists($this, $method)) { + $this->$method($xmlWriter, $style); + } + + // Child style + $styleWriter = new ShapeStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $xmlWriter->endElement(); // v:$type + $xmlWriter->endElement(); // w:pict + $xmlWriter->endElement(); // w:r + + if (!$this->withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write arc + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Shape $style + */ + private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) + { + $points = $this->getPoints('arc', $style->getPoints()); + + $xmlWriter->writeAttributeIf($points['start'] !== null, 'startAngle', $points['start']); + $xmlWriter->writeAttributeIf($points['end'] !== null, 'endAngle', $points['end']); + } + + /** + * Write curve + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Shape $style + */ + private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) + { + $points = $this->getPoints('curve', $style->getPoints()); + + $this->writeLine($xmlWriter, $style); + $xmlWriter->writeAttributeIf($points['point1'] !== null, 'control1', $points['point1']); + $xmlWriter->writeAttributeIf($points['point2'] !== null, 'control2', $points['point2']); + } + + /** + * Write line + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Shape $style + */ + private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) + { + $points = $this->getPoints('line', $style->getPoints()); + + $xmlWriter->writeAttributeIf($points['start'] !== null, 'from', $points['start']); + $xmlWriter->writeAttributeIf($points['end'] !== null, 'to', $points['end']); + } + + /** + * Write polyline + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Shape $style + */ + private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) + { + $xmlWriter->writeAttributeIf($style->getPoints() !== null, 'points', $style->getPoints()); + } + + /** + * Write rectangle + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Shape $style + */ + private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style) + { + $xmlWriter->writeAttribute('arcsize', $style->getRoundness()); + } + + /** + * Set points + * + * @param string $type + * @param array $value + * @return array + */ + private function getPoints($type, $value) + { + $points = array(); + + switch ($type) { + case 'arc': + case 'line': + $points = explode(' ', $value); + @list($start, $end) = $points; + $points = array('start' => $start, 'end' => $end); + break; + case 'curve': + $points = explode(' ', $value); + @list($start, $end, $point1, $point2) = $points; + $points = array('start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2); + break; + } + + return $points; + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 61c8bae8..d91e37b8 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -102,4 +102,40 @@ abstract class AbstractStyle return $value * $factor; } + + /** + * Write child style + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $name + * @param mixed $value + */ + protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value) + { + if ($value !== null) { + $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\" . $name; + + /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */ + $writer = new $class($xmlWriter, $value); + $writer->write(); + } + } + + /** + * Assemble style array into style string + * + * @param array $styles + * @return string + */ + protected function assembleStyle($styles = array()) + { + $style = ''; + foreach ($styles as $key => $value) { + if (!is_null($value) && $value != '') { + $style .= "{$key}:{$value}; "; + } + } + + return trim($style); + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php new file mode 100644 index 00000000..aa8ba1ea --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -0,0 +1,44 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Extrusion) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement("o:extrusion"); + $xmlWriter->writeAttribute('on', 't'); + $xmlWriter->writeAttributeIf($style->getType() !== null, 'type', $style->getType()); + $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php new file mode 100644 index 00000000..0695f8ef --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -0,0 +1,41 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Fill) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->writeAttribute('on', 't'); + $xmlWriter->writeAttributeIf($style->getColor() !== null, 'fillcolor', $style->getColor()); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php new file mode 100644 index 00000000..dd2337ee --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -0,0 +1,56 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Frame) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $styles = array(); + $properties = array( + 'left' => 'margin-left', + 'top' => 'margin-top', + 'width' => 'width', + 'height' => 'height', + ); + + foreach ($properties as $key => $property) { + $method = "get{$key}"; + $value = $style->$method(); + if ($value !== null) { + $styles[$property] = $style->$method() . 'pt'; + } + } + + $xmlWriter->writeAttribute('style', $this->assembleStyle($styles)); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 280b569a..aebc93c1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -152,22 +152,4 @@ class Image extends AbstractStyle return $styles; } - - /** - * Assemble style array into style string - * - * @param array $styles - * @return string - */ - protected function assembleStyle($styles = array()) - { - $style = ''; - foreach ($styles as $key => $value) { - if (!is_null($value) && $value != '') { - $style .= "{$key}:{$value}; "; - } - } - - return trim($style); - } } diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php new file mode 100644 index 00000000..5003d9fc --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -0,0 +1,48 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Outline) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement("v:stroke"); + $xmlWriter->writeAttribute('on', 't'); + $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); + $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . 'pt'); + $xmlWriter->writeAttributeIf($style->getDash() !== null, 'dashstyle', $style->getDash()); + $xmlWriter->writeAttributeIf($style->getLine() !== null, 'linestyle', $style->getLine()); + $xmlWriter->writeAttributeIf($style->getStartArrow() !== null, 'startarrow', $style->getStartArrow()); + $xmlWriter->writeAttributeIf($style->getEndArrow() !== null, 'endarrow', $style->getEndArrow()); + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index f3287700..0e97a7d7 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -110,24 +110,6 @@ class Paragraph extends AbstractStyle } } - /** - * Write child style - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param string $name - * @param mixed $value - */ - private function writeChildStyle(XMLWriter $xmlWriter, $name, $value) - { - if ($value !== null) { - $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\" . $name; - - /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */ - $writer = new $class($xmlWriter, $value); - $writer->write(); - } - } - /** * Write tabs * diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php new file mode 100644 index 00000000..dd7c769a --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -0,0 +1,44 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Shadow) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement("v:shadow"); + $xmlWriter->writeAttribute('on', 't'); + $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); + $xmlWriter->writeAttributeIf($style->getOffset() !== null, 'offset', $style->getOffset()); + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php new file mode 100644 index 00000000..7eafb18e --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -0,0 +1,45 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Shape) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + + $childStyles = array('Frame', 'Fill', 'Outline', 'Shadow', 'Extrusion'); + foreach ($childStyles as $childStyle) { + $method = "get{$childStyle}"; + $this->writeChildStyle($xmlWriter, $childStyle, $style->$method()); + } + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index da7504b5..6ba3477b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -41,7 +41,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', - 'Field', 'Line' + 'Field', 'Line', 'Shape' ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; @@ -61,10 +61,91 @@ class ElementTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $section = $phpWord->addSection(); + $section->addLine(array('width' => 1000, 'height' => 1000, 'positioning' => 'absolute', 'flip' => true)); $doc = TestHelperDOCX::getDocument($phpWord); $element = "/w:document/w:body/w:p/w:r/w:pict/v:shapetype"; $this->assertTrue($doc->elementExists($element)); } + + /** + * Test shape elements + */ + public function testShapeElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + // Arc + $section->addShape( + 'arc', + array( + 'points' => '-90 20', + 'frame' => array('width' => 120, 'height' => 120), + 'outline' => array('color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'), + ) + ); + + // Curve + $section->addShape( + 'curve', + array( + 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow', + 'outline' => array('color' => '#66cc00', 'weight' => 2, 'dash' => 'dash', + 'startArrow' => 'diamond', 'endArrow' => 'block'), + ) + ); + + // Line + $section->addShape( + 'line', + array( + 'points' => '1,1 150,30', + 'outline' => array('color' => '#cc00ff', 'line' => 'thickThin', 'weight' => 3, + 'startArrow' => 'oval', 'endArrow' => 'classic'), + ) + ); + + // Polyline + $section->addShape( + 'polyline', + array( + 'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50', + 'outline' => array('color' => '#cc6666', 'weight' => 2, + 'startArrow' => 'none', 'endArrow' => 'classic'), + ) + ); + + // Rectangle + $section->addShape( + 'rect', + array( + 'roundness' => 0.2, + 'frame' => array('width' => 100, 'height' => 100, 'left' => 1, 'top' => 1), + 'fill' => array('color' => '#FFCC33'), + 'outline' => array('color' => '#990000', 'weight' => 1), + 'shadow' => array('color' => '#EEEEEE', 'offset' => '3pt,3pt'), + ) + ); + + // Oval + $section->addShape( + 'oval', + array( + 'frame' => array('width' => 100, 'height' => 70, 'left' => 1, 'top' => 1), + 'fill' => array('color' => '#33CC99'), + 'outline' => array('color' => '#333333', 'weight' => 2), + 'extrusion' => array('type' => 'perspective', 'color' => '#EEEEEE'), + ) + ); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $elements = array('arc', 'curve', 'line', 'polyline', 'roundrect', 'oval'); + foreach ($elements as $element) { + $path = "/w:document/w:body/w:p/w:r/w:pict/v:{$element}"; + $this->assertTrue($doc->elementExists($path)); + } + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php index 71cbc300..c840d207 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php @@ -31,7 +31,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase $styles = array( 'Alignment', 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering', 'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table', - 'TextBox', 'Line' + 'TextBox', 'Line', 'Shape', 'Frame', 'Outline', 'Fill', 'Shadow', 'Extrusion', ); foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style; From 61d8dbde49ffc6f7b643ec9da2fcd42d35afa1f0 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 2 Jun 2014 22:57:11 +0700 Subject: [PATCH 235/326] QA: Small fixes for #258 based on Scrutinizer https://scrutinizer-ci.com/g/PHPOffice/PHPWord/inspections/54c74458-884d-4299-aed1-a7d2eb6a5654 --- src/PhpWord/Writer/HTML/Style/Font.php | 1 - src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 18f28287..8645a1f4 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer\HTML\Style; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font as FontStyle; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index f4ac2efb..5590861c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -143,7 +143,7 @@ class Shape extends AbstractElement * Set points * * @param string $type - * @param array $value + * @param string $value * @return array */ private function getPoints($type, $value) From e3dd4494f3f0864bc7e21de5b208a70bb38911a4 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 2 Jun 2014 23:33:10 +0700 Subject: [PATCH 236/326] #238: Known issue about read/write permission on temp folder --- CHANGELOG.md | 2 +- README.md | 4 ++++ samples/index.php | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36c27c26..7c9d370a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ None yet. ### Miscellaneous -None yet. +- Docs: Add known issue on `README` about requirement for temporary folder to be writable and update `samples/index.php` for this requirement check - @ivanlanin GH-238 ## 0.11.1 - 2 June 2014 diff --git a/README.md b/README.md index ecbe1354..fefde4eb 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,10 @@ $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); $objWriter->save('helloWorld.rtf'); ``` +## Known issues + +- GH-238: PHPWord uses temporary folder with `sys_get_temp_dir()` extensively. The default setting on some systems (especially Windows) do not give appropriate read/write permission to this folder. Run `samples/index.php` either by CLI or by web browsers to check if you have this requirement fulfilled. + ## Contributing We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute: diff --git a/samples/index.php b/samples/index.php index 420c5420..8e466d97 100644 --- a/samples/index.php +++ b/samples/index.php @@ -3,6 +3,7 @@ include_once 'Sample_Header.php'; $requirements = array( 'php' => array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), 'xml' => array('PHP extension XML', extension_loaded('xml')), + 'temp' => array('Temp folder "' . sys_get_temp_dir() . '" is writable', is_writable(sys_get_temp_dir())), 'zip' => array('PHP extension ZipArchive (optional)', extension_loaded('zip')), 'gd' => array('PHP extension GD (optional)', extension_loaded('gd')), 'xmlw' => array('PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')), @@ -34,6 +35,7 @@ if (!CLI) { echo 'Requirement check:' . PHP_EOL; foreach ($requirements as $key => $value) { list($label, $result) = $value; + $label = strip_tags($label); $status = $result ? '32m passed' : '31m failed'; echo "{$label} ... \033[{$status}\033[0m" . PHP_EOL; } From 9c8620ecd79887d90b38c0003b966f6aebf17ab8 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 2 Jun 2014 23:47:44 +0700 Subject: [PATCH 237/326] Refactor `IOFactory` to remove duplication --- src/PhpWord/IOFactory.php | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 166ea152..70b525f8 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -27,19 +27,13 @@ abstract class IOFactory /** * Create new writer * - * @param PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $name * @return \PhpOffice\PhpWord\Writer\WriterInterface - * @throws \PhpOffice\PhpWord\Exception\Exception */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - $class = 'PhpOffice\\PhpWord\\Writer\\' . $name; - if (class_exists($class) && self::isConcreteClass($class)) { - return new $class($phpWord); - } else { - throw new Exception("\"{$name}\" is not a valid writer."); - } + return self::createObject('Writer', $name, $phpWord); } /** @@ -47,15 +41,28 @@ abstract class IOFactory * * @param string $name * @return \PhpOffice\PhpWord\Reader\ReaderInterface - * @throws \PhpOffice\PhpWord\Exception\Exception */ public static function createReader($name = 'Word2007') { - $class = 'PhpOffice\\PhpWord\\Reader\\' . $name; + return self::createObject('Reader', $name); + } + + /** + * Create new object + * + * @param string $type + * @param string $name + * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return \PhpOffice\PhpWord\Writer\WriterInterface|\PhpOffice\PhpWord\Reader\ReaderInterface + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + private static function createObject($type, $name, $phpWord = null) + { + $class = "PhpOffice\\PhpWord\\{$type}\\{$name}"; if (class_exists($class) && self::isConcreteClass($class)) { - return new $class(); + return new $class($phpWord); } else { - throw new Exception("\"{$name}\" is not a valid reader."); + throw new Exception("\"{$name}\" is not a valid {$type}."); } } @@ -64,7 +71,7 @@ abstract class IOFactory * * @param string $filename The name of the file * @param string $readerName - * @return PhpWord + * @return \PhpOffice\PhpWord\PhpWord $phpWord */ public static function load($filename, $readerName = 'Word2007') { From a2294b4b1ed13061eb9f140390216816ab92fb79 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 4 Jun 2014 22:57:59 +0700 Subject: [PATCH 238/326] Font: New `scale`, `spacing`, and `kerning` property of font style --- CHANGELOG.md | 1 + samples/Sample_01_SimpleText.php | 43 +++- src/PhpWord/IOFactory.php | 1 + src/PhpWord/Style/AbstractStyle.php | 36 ++++ src/PhpWord/Style/Font.php | 200 ++++++++++++++---- src/PhpWord/Style/Paragraph.php | 30 +-- src/PhpWord/Writer/Word2007/Style/Font.php | 11 +- tests/PhpWord/Tests/Style/FontTest.php | 6 + .../Writer/Word2007/Part/DocumentTest.php | 3 +- 9 files changed, 244 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9d370a..316f92bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Features - Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin GH-123 +- Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin ### Bugfixes diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 311f3350..8c93f917 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -23,22 +23,43 @@ $section->addText('I am styled by a font style definition.', 'rStyle'); $section->addText('I am styled by a paragraph style definition.', null, 'pStyle'); $section->addText('I am styled by both font and paragraph style.', 'rStyle', 'pStyle'); -$section->addPageBreak(); +$section->addTextBreak(); // Inline font style $fontStyle['name'] = 'Times New Roman'; $fontStyle['size'] = 20; -$fontStyle['bold'] = true; -$fontStyle['italic'] = true; -$fontStyle['underline'] = 'dash'; -$fontStyle['strikethrough'] = true; -$fontStyle['superScript'] = true; -$fontStyle['color'] = 'FF0000'; -$fontStyle['fgColor'] = 'yellow'; -$fontStyle['smallCaps'] = true; -$section->addText('I am inline styled.', $fontStyle); -$section->addTextBreak(); +$textrun = $section->addTextRun(); +$textrun->addText('I am inline styled ', $fontStyle); +$textrun->addText('with '); +$textrun->addText('color', array('color' => '996699')); +$textrun->addText(', '); +$textrun->addText('bold', array('bold' => true)); +$textrun->addText(', '); +$textrun->addText('italic', array('italic' => true)); +$textrun->addText(', '); +$textrun->addText('underline', array('underline' => 'dash')); +$textrun->addText(', '); +$textrun->addText('strikethrough', array('strikethrough' => true)); +$textrun->addText(', '); +$textrun->addText('doubleStrikethrough', array('doubleStrikethrough' => true)); +$textrun->addText(', '); +$textrun->addText('superScript', array('superScript' => true)); +$textrun->addText(', '); +$textrun->addText('subScript', array('subScript' => true)); +$textrun->addText(', '); +$textrun->addText('smallCaps', array('smallCaps' => true)); +$textrun->addText(', '); +$textrun->addText('allCaps', array('allCaps' => true)); +$textrun->addText(', '); +$textrun->addText('fgColor', array('fgColor' => 'yellow')); +$textrun->addText(', '); +$textrun->addText('scale', array('scale' => 200)); +$textrun->addText(', '); +$textrun->addText('spacing', array('spacing' => 120)); +$textrun->addText(', '); +$textrun->addText('kerning', array('kerning' => 10)); +$textrun->addText('. '); // Link $section->addLink('http://www.google.com', 'Google'); diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 70b525f8..9b51af06 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -75,6 +75,7 @@ abstract class IOFactory */ public static function load($filename, $readerName = 'Word2007') { + /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ $reader = self::createReader($readerName); return $reader->load($filename); diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 4d375888..cc275fc6 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -126,6 +126,24 @@ abstract class AbstractStyle return $this; } + /** + * Return style value of child style object, e.g. `left` from `Indentation` child style of `Paragraph` + * + * @param \PhpOffice\PhpWord\Style\AbstractStyle $substyleObject + * @param string $substyleProperty + * @return mixed + * @since 0.12.0 + */ + public function getChildStyleValue($substyleObject, $substyleProperty) + { + if ($substyleObject !== null) { + $method = "get{$substyleProperty}"; + return $substyleObject->$method(); + } else { + return null; + } + } + /** * Set style value template method * @@ -296,6 +314,24 @@ abstract class AbstractStyle return $style; } + /** + * Set $property value and set $pairProperty = false when $value = true + * + * @param bool $property + * @param bool $pairProperty + * @param bool $value + * @return self + */ + protected function setPairedVal(&$property, &$pairProperty, $value) + { + $property = $this->setBoolVal($value, $property); + if ($value == true) { + $pairProperty = false; + } + + return $this; + } + /** * Set style using associative array * diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 0775b8b3..000e2bb6 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -182,10 +182,31 @@ class Font extends AbstractStyle private $fgColor; /** - * Text line height + * Expanded/compressed text: 0-600 (percent) * * @var int + * @since 0.12.0 + * @link http://www.schemacentral.com/sc/ooxml/e-w_w-1.html */ + private $scale; + + /** + * Character spacing adjustment: twip + * + * @var int|float + * @since 0.12.0 + * @link http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html + */ + private $spacing; + + /** + * Font kerning: halfpoint + * + * @var int|float + * @since 0.12.0 + * @link http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html + */ + private $kerning; /** * Paragraph style @@ -213,6 +234,46 @@ class Font extends AbstractStyle $this->setParagraph($paragraph); } + /** + * Get style values + * + * @return array + * @since 0.12.0 + */ + public function getStyleValues() + { + $styles = array( + 'name' => $this->getStyleName(), + 'basic' => array( + 'name' => $this->getName(), + 'size' => $this->getSize(), + 'color' => $this->getColor(), + 'hint' => $this->getHint(), + ), + 'style' => array( + 'bold' => $this->isBold(), + 'italic' => $this->isItalic(), + 'underline' => $this->getUnderline(), + 'strike' => $this->isStrikethrough(), + 'dStrike' => $this->isDoubleStrikethrough(), + 'super' => $this->isSuperScript(), + 'sub' => $this->isSubScript(), + 'smallCaps' => $this->isSmallCaps(), + 'allCaps' => $this->isAllCaps(), + 'fgColor' => $this->getFgColor(), + ), + 'spacing' => array( + 'scale' => $this->getScale(), + 'spacing' => $this->getSpacing(), + 'kerning' => $this->getKerning(), + ), + 'paragraph' => $this->getParagraph(), + 'shading' => $this->getShading(), + ); + + return $styles; + } + /** * Get style type * @@ -236,7 +297,7 @@ class Font extends AbstractStyle /** * Set font name * - * @param string $value + * @param string $value * @return self */ public function setName($value = null) @@ -259,7 +320,7 @@ class Font extends AbstractStyle /** * Set Font Content Type * - * @param string $value + * @param string $value * @return self */ public function setHint($value = null) @@ -272,7 +333,7 @@ class Font extends AbstractStyle /** * Get font size * - * @return int|float + * @return int|float */ public function getSize() { @@ -282,7 +343,7 @@ class Font extends AbstractStyle /** * Set font size * - * @param int|float $value + * @param int|float $value * @return self */ public function setSize($value = null) @@ -305,7 +366,7 @@ class Font extends AbstractStyle /** * Set font color * - * @param string $value + * @param string $value * @return self */ public function setColor($value = null) @@ -328,7 +389,7 @@ class Font extends AbstractStyle /** * Set bold * - * @param bool $value + * @param bool $value * @return self */ public function setBold($value = true) @@ -351,7 +412,7 @@ class Font extends AbstractStyle /** * Set italic * - * @param bool $value + * @param bool $value * @return self */ public function setItalic($value = true) @@ -374,7 +435,7 @@ class Font extends AbstractStyle /** * Set underline * - * @param string $value + * @param string $value * @return self */ public function setUnderline($value = self::UNDERLINE_NONE) @@ -397,12 +458,12 @@ class Font extends AbstractStyle /** * Set superscript * - * @param bool $value + * @param bool $value * @return self */ public function setSuperScript($value = true) { - return $this->setPairedProperty($this->superScript, $this->subScript, $value); + return $this->setPairedVal($this->superScript, $this->subScript, $value); } /** @@ -418,12 +479,12 @@ class Font extends AbstractStyle /** * Set subscript * - * @param bool $value + * @param bool $value * @return self */ public function setSubScript($value = true) { - return $this->setPairedProperty($this->subScript, $this->superScript, $value); + return $this->setPairedVal($this->subScript, $this->superScript, $value); } /** @@ -439,12 +500,12 @@ class Font extends AbstractStyle /** * Set strikethrough * - * @param bool $value + * @param bool $value * @return self */ public function setStrikethrough($value = true) { - return $this->setPairedProperty($this->strikethrough, $this->doubleStrikethrough, $value); + return $this->setPairedVal($this->strikethrough, $this->doubleStrikethrough, $value); } /** @@ -460,12 +521,12 @@ class Font extends AbstractStyle /** * Set double strikethrough * - * @param bool $value + * @param bool $value * @return self */ public function setDoubleStrikethrough($value = true) { - return $this->setPairedProperty($this->doubleStrikethrough, $this->strikethrough, $value); + return $this->setPairedVal($this->doubleStrikethrough, $this->strikethrough, $value); } /** @@ -481,12 +542,12 @@ class Font extends AbstractStyle /** * Set small caps * - * @param bool $value + * @param bool $value * @return self */ public function setSmallCaps($value = true) { - return $this->setPairedProperty($this->smallCaps, $this->allCaps, $value); + return $this->setPairedVal($this->smallCaps, $this->allCaps, $value); } /** @@ -502,12 +563,12 @@ class Font extends AbstractStyle /** * Set all caps * - * @param bool $value + * @param bool $value * @return self */ public function setAllCaps($value = true) { - return $this->setPairedProperty($this->allCaps, $this->smallCaps, $value); + return $this->setPairedVal($this->allCaps, $this->smallCaps, $value); } /** @@ -523,7 +584,7 @@ class Font extends AbstractStyle /** * Set foreground/highlight color * - * @param string $value + * @param string $value * @return self */ public function setFgColor($value = null) @@ -540,11 +601,7 @@ class Font extends AbstractStyle */ public function getBgColor() { - if ($this->shading !== null) { - return $this->shading->getFill(); - } else { - return null; - } + return $this->getChildStyleValue($this->shading, 'fill'); } /** @@ -558,6 +615,75 @@ class Font extends AbstractStyle $this->setShading(array('fill' => $value)); } + /** + * Get scale + * + * @return int + */ + public function getScale() + { + return $this->scale; + } + + /** + * Set scale + * + * @param int $value + * @return self + */ + public function setScale($value = null) + { + $this->scale = $this->setIntVal($value, null); + + return $this; + } + + /** + * Get font spacing + * + * @return int|float + */ + public function getSpacing() + { + return $this->spacing; + } + + /** + * Set font spacing + * + * @param int|float $value + * @return self + */ + public function setSpacing($value = null) + { + $this->spacing = $this->setNumericVal($value, null); + + return $this; + } + + /** + * Get font kerning + * + * @return int|float + */ + public function getKerning() + { + return $this->kerning; + } + + /** + * Set font kerning + * + * @param int|float $value + * @return self + */ + public function setKerning($value = null) + { + $this->kerning = $this->setNumericVal($value, null); + + return $this; + } + /** * Get line height * @@ -571,7 +697,7 @@ class Font extends AbstractStyle /** * Set lineheight * - * @param int|float|string $value + * @param int|float|string $value * @return self */ public function setLineHeight($value) @@ -627,24 +753,6 @@ class Font extends AbstractStyle return $this; } - /** - * Set $property value and set $pairProperty = false when $value = true - * - * @param bool $property - * @param bool $pairProperty - * @param bool $value - * @return self - */ - private function setPairedProperty(&$property, &$pairProperty, $value) - { - $property = $this->setBoolVal($value, $property); - if ($value == true) { - $pairProperty = false; - } - - return $this; - } - /** * Get bold * diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 81673586..a5576067 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -313,11 +313,7 @@ class Paragraph extends AbstractStyle */ public function getIndent() { - if ($this->indentation !== null) { - return $this->indentation->getLeft(); - } else { - return null; - } + return $this->getChildStyleValue($this->indentation, 'left'); } /** @@ -338,11 +334,7 @@ class Paragraph extends AbstractStyle */ public function getHanging() { - if ($this->indentation !== null) { - return $this->indentation->getHanging(); - } else { - return null; - } + return $this->getChildStyleValue($this->indentation, 'hanging'); } /** @@ -388,11 +380,7 @@ class Paragraph extends AbstractStyle */ public function getSpaceBefore() { - if ($this->spacing !== null) { - return $this->spacing->getBefore(); - } else { - return null; - } + return $this->getChildStyleValue($this->spacing, 'before'); } /** @@ -413,11 +401,7 @@ class Paragraph extends AbstractStyle */ public function getSpaceAfter() { - if ($this->spacing !== null) { - return $this->spacing->getAfter(); - } else { - return null; - } + return $this->getChildStyleValue($this->spacing, 'after'); } /** @@ -438,11 +422,7 @@ class Paragraph extends AbstractStyle */ public function getSpacing() { - if ($this->spacing !== null) { - return $this->spacing->getLine(); - } else { - return null; - } + return $this->getChildStyleValue($this->spacing, 'line'); } /** diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 0ef22f08..73673f05 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -103,17 +103,20 @@ class Font extends AbstractStyle $xmlWriter->writeElementIf($style->isAllCaps(), 'w:caps'); // Underline - $underline = $style->getUnderline(); - $xmlWriter->writeElementIf($underline != 'none', 'w:u', 'w:val', $underline); + $xmlWriter->writeElementIf($style->getUnderline() != 'none', 'w:u', 'w:val', $style->getUnderline()); // Foreground-Color - $fgColor = $style->getFgColor(); - $xmlWriter->writeElementIf(!is_null($fgColor), 'w:highlight', 'w:val', $fgColor); + $xmlWriter->writeElementIf($style->getFgColor() !== null, 'w:highlight', 'w:val', $style->getFgColor()); // Superscript/subscript $xmlWriter->writeElementIf($style->isSuperScript(), 'w:vertAlign', 'w:val', 'superscript'); $xmlWriter->writeElementIf($style->isSubScript(), 'w:vertAlign', 'w:val', 'subscript'); + // Spacing + $xmlWriter->writeElementIf($style->getScale() !== null, 'w:w', 'w:val', $style->getScale()); + $xmlWriter->writeElementIf($style->getSpacing() !== null, 'w:spacing', 'w:val', $style->getSpacing()); + $xmlWriter->writeElementIf($style->getKerning() !== null, 'w:kern', 'w:val', $style->getKerning() * 2); + // Background-Color $shading = $style->getShading(); if (!is_null($shading)) { diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 432b29fb..9e74af2f 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -71,6 +71,9 @@ class FontTest extends \PHPUnit_Framework_TestCase 'allCaps' => false, 'fgColor' => null, 'bgColor' => null, + 'scale' => null, + 'spacing' => null, + 'kerning' => null, ); foreach ($attributes as $key => $default) { $get = is_bool($default) ? "is{$key}" : "get{$key}"; @@ -106,6 +109,9 @@ class FontTest extends \PHPUnit_Framework_TestCase 'fgColor' => Font::FGCOLOR_YELLOW, 'bgColor' => 'FFFF00', 'lineHeight' => 2, + 'scale' => 150, + 'spacing' => 240, + 'kerning' => 10, ); $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index e27d072a..5e0dc747 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -136,7 +136,8 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $tabs = array(new \PhpOffice\PhpWord\Style\Tab('right', 9090)); $phpWord = new PhpWord(); $phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'tabs' => $tabs)); // Style #1 - $phpWord->addFontStyle('fStyle', array('size' => '20', 'bold' => true, 'allCaps' => true)); // Style #2 + $phpWord->addFontStyle('fStyle', array('size' => '20', 'bold' => true, 'allCaps' => true, + 'scale' => 200, 'spacing' => 240, 'kerning' => 10)); // Style #2 $phpWord->addTitleStyle(1, array('color' => '333333', 'doubleStrikethrough' => true)); // Style #3 $phpWord->addTableStyle('tStyle', array('borderSize' => 1)); $fontStyle = new Font('text', array('align' => 'center')); From d57606082db85f52a30ac924b1972c58579e1aec Mon Sep 17 00:00:00 2001 From: Andrew Collins Date: Wed, 4 Jun 2014 13:27:18 -0400 Subject: [PATCH 239/326] Fix rare PclZip/realpath/PHP version problem In PHP 5.4.4 realpath() handles absolute paths correctly, but in PHP 5.3.8 returns false. --- src/PhpWord/Shared/ZipArchive.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index cbfcb071..c5d56b01 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -218,7 +218,10 @@ class ZipArchive { /** @var \PclZip $zip Type hint */ $zip = $this->zip; - $filename = realpath($filename); + $test_filename = realpath($filename); + if($test_filename !== false) { + $filename = $test_filename; + } $filenameParts = pathinfo($filename); $localnameParts = pathinfo($localname); From 2328e34e64d3d045d821f44212d3a4e2da5459c2 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 3 Jun 2014 14:13:35 +0700 Subject: [PATCH 240/326] Refactor Word2007/Element to identify the same properties --- .../Word2007/Element/AbstractElement.php | 10 ++++++++++ .../Writer/Word2007/Element/CheckBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/Field.php | 2 +- .../Writer/Word2007/Element/Footnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/Image.php | 19 ++++++++++++++----- src/PhpWord/Writer/Word2007/Element/Line.php | 15 ++++++++++----- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- .../Writer/Word2007/Element/Object.php | 14 +++++++++++--- .../Writer/Word2007/Element/PreserveText.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 7 +++---- src/PhpWord/Writer/Word2007/Element/Text.php | 14 +------------- .../Writer/Word2007/Element/TextBox.php | 7 ++++--- .../Writer/Word2007/Element/TextBreak.php | 4 +++- .../Writer/Word2007/Element/TextRun.php | 2 +- 14 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 52b4c62e..c1e721ed 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -115,6 +115,16 @@ abstract class AbstractElement $this->pageBreakBefore = (bool)$value; } + /** + * Write ending + */ + protected function endElementP() + { + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } + /** * Convert text to valid format * diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index ea13b8f9..2d0fe691 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -85,6 +85,6 @@ class CheckBox extends Text $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r - $this->writeClosingWP(); + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 68c4c40c..1e538e1a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -82,6 +82,6 @@ class Field extends Text $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:fldSimple - $this->writeClosingWP(); + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 240a8a00..05b96ae5 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -55,6 +55,6 @@ class Footnote extends Text $xmlWriter->endElement(); // w:$referenceType $xmlWriter->endElement(); // w:r - $this->writeClosingWP(); + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index a882040e..963e2da1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -52,6 +52,7 @@ class Image extends AbstractElement private function writeImage(XMLWriter $xmlWriter, ImageElement $element) { $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0); + $style = $element->getStyle(); $styleWriter = new ImageStyleWriter($xmlWriter, $style); @@ -59,23 +60,25 @@ class Image extends AbstractElement $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t75'); + $styleWriter->write(); + $styleWriter->writeW10Wrap(); + $xmlWriter->startElement('v:imagedata'); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->writeAttribute('o:title', ''); $xmlWriter->endElement(); // v:imagedata - $styleWriter->writeW10Wrap(); + $xmlWriter->endElement(); // v:shape $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - if (!$this->withoutP) { - $xmlWriter->endElement(); // w:p - } + $this->endElementP(); // w:p } /** * Write watermark element @@ -83,23 +86,29 @@ class Image extends AbstractElement private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) { $rId = $element->getRelationId(); + $style = $element->getStyle(); - $style->setPositioning('absolute'); $styleWriter = new ImageStyleWriter($xmlWriter, $style); $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t75'); + + $style->setPositioning('absolute'); $styleWriter->write(); + $xmlWriter->startElement('v:imagedata'); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->writeAttribute('o:title', ''); $xmlWriter->endElement(); // v:imagedata + $xmlWriter->endElement(); // v:shape $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index 1ae10694..ce576030 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -37,16 +37,19 @@ class Line extends AbstractElement return; } - $style = $element->getStyle(); + $style = $element->getStyle(); $styleWriter = new LineStyleWriter($xmlWriter, $style); $elementId = $element->getElementIndex(); + if (!$this->withoutP) { $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); + // Shapetype could be defined for each line separately, but then a unique id would be necessary if ($elementId == 1) { $xmlWriter->startElement('v:shapetype'); @@ -67,18 +70,20 @@ class Line extends AbstractElement $xmlWriter->endElement(); // o:lock $xmlWriter->endElement(); // v:shapetype } + $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('id', sprintf('_x0000_s1%1$03d', $elementId)); $xmlWriter->writeAttribute('type', '#_x0000_t32'); //type should correspond to shapetype id + $styleWriter->write(); - $styleWriter->writeStroke(); $styleWriter->writeW10Wrap(); + $styleWriter->writeStroke(); + $xmlWriter->endElement(); // v:shape + $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - if (!$this->withoutP) { - $xmlWriter->endElement(); // w:p - } + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index ec531bac..68851ec4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -53,6 +53,6 @@ class Link extends Text $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:hyperlink - $this->writeClosingWP(); + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index ae03f04f..f172f81b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -41,6 +41,7 @@ class Object extends AbstractElement $rIdImage = $element->getImageRelationId() + ($element->isInSection() ? 6 : 0); $shapeId = md5($rIdObject . '_' . $rIdImage); $objectId = $element->getRelationId() + 1325353440; + $style = $element->getStyle(); $styleWriter = new ImageStyleWriter($xmlWriter, $style); @@ -48,20 +49,27 @@ class Object extends AbstractElement $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:object'); $xmlWriter->writeAttribute('w:dxaOrig', '249'); $xmlWriter->writeAttribute('w:dyaOrig', '160'); + + // Icon $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('id', $shapeId); $xmlWriter->writeAttribute('type', '#_x0000_t75'); $xmlWriter->writeAttribute('style', 'width:104px;height:67px'); $xmlWriter->writeAttribute('o:ole', ''); + $xmlWriter->startElement('v:imagedata'); $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); $xmlWriter->writeAttribute('o:title', ''); $xmlWriter->endElement(); // v:imagedata + $xmlWriter->endElement(); // v:shape + + // Object $xmlWriter->startElement('o:OLEObject'); $xmlWriter->writeAttribute('Type', 'Embed'); $xmlWriter->writeAttribute('ProgID', 'Package'); @@ -70,10 +78,10 @@ class Object extends AbstractElement $xmlWriter->writeAttribute('ObjectID', '_' . $objectId); $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); $xmlWriter->endElement(); // o:OLEObject + $xmlWriter->endElement(); // w:object $xmlWriter->endElement(); // w:r - if (!$this->withoutP) { - $xmlWriter->endElement(); // w:p - } + + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index dd5d9008..c63d13a7 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -86,6 +86,6 @@ class PreserveText extends Text } } - $this->writeClosingWP(); + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 5590861c..649e7384 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -42,6 +42,8 @@ class Shape extends AbstractElement } $style = $element->getStyle(); + $styleWriter = new ShapeStyleWriter($xmlWriter, $style); + $type = $element->getType(); if ($type == 'rect' && $style->getRoundness() !== null) { $type = 'roundrect'; @@ -62,16 +64,13 @@ class Shape extends AbstractElement } // Child style - $styleWriter = new ShapeStyleWriter($xmlWriter, $style); $styleWriter->write(); $xmlWriter->endElement(); // v:$type $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - if (!$this->withoutP) { - $xmlWriter->endElement(); // w:p - } + $this->endElementP(); // w:p } /** diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 64c4b766..5d92b3f9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -51,7 +51,7 @@ class Text extends AbstractElement $xmlWriter->endElement(); $xmlWriter->endElement(); // w:r - $this->writeClosingWP(); + $this->endElementP(); // w:p } /** @@ -78,18 +78,6 @@ class Text extends AbstractElement } } - /** - * Write ending - */ - protected function writeClosingWP() - { - $xmlWriter = $this->getXmlWriter(); - - if (!$this->withoutP) { - $xmlWriter->endElement(); // w:p - } - } - /** * Write ending */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 4ee5e68e..00fac58e 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -36,6 +36,7 @@ class TextBox extends AbstractElement if (!$element instanceof \PhpOffice\PhpWord\Element\TextBox) { return; } + $style = $element->getStyle(); $styleWriter = new TextBoxStyleWriter($xmlWriter, $style); @@ -48,7 +49,9 @@ class TextBox extends AbstractElement $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t0202'); + $styleWriter->write(); + $xmlWriter->startElement('v:textbox'); $styleWriter->writeInnerMargin(); @@ -64,8 +67,6 @@ class TextBox extends AbstractElement $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - if (!$this->withoutP) { - $xmlWriter->endElement(); // w:p - } + $this->endElementP(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 5f4bd3ce..2995e8be 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -38,12 +38,14 @@ class TextBreak extends Text if (!$this->withoutP) { $hasStyle = $element->hasStyle(); $this->writeOpeningWP(); + if ($hasStyle) { $xmlWriter->startElement('w:pPr'); $this->writeFontStyle(); $xmlWriter->endElement(); // w:pPr } - $this->writeClosingWP(); + + $this->endElementP(); // w:p } else { $xmlWriter->writeElement('w:br'); } diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index 330e297c..ca3a6b05 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -37,6 +37,6 @@ class TextRun extends Text $containerWriter = new Container($xmlWriter, $element); $containerWriter->write(); - $this->writeClosingWP(); + $this->endElementP(); // w:p } } From 1accec2ff0e0b1b97ce2759ede3cce5a4bcc8ea9 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 5 Jun 2014 12:52:39 +0700 Subject: [PATCH 241/326] Refactor styles: Inherit Image and Line from Frame --- src/PhpWord/Style/Frame.php | 316 ++++++++++++++++++ src/PhpWord/Style/Image.php | 296 +++------------- src/PhpWord/Style/Outline.php | 60 ++++ src/PhpWord/Writer/Word2007/Element/Image.php | 10 +- src/PhpWord/Writer/Word2007/Element/Line.php | 1 - .../Writer/Word2007/Element/TextBox.php | 8 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 115 ++++++- src/PhpWord/Writer/Word2007/Style/Image.php | 130 +------ src/PhpWord/Writer/Word2007/Style/Line.php | 72 +--- src/PhpWord/Writer/Word2007/Style/Outline.php | 3 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 86 +---- tests/PhpWord/Tests/Style/FontTest.php | 1 + .../Tests/Writer/Word2007/ElementTest.php | 2 +- .../Tests/Writer/Word2007/StyleTest.php | 5 +- 14 files changed, 578 insertions(+), 527 deletions(-) diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index fce3f4a9..21b27716 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -27,6 +27,80 @@ namespace PhpOffice\PhpWord\Style; */ class Frame extends AbstractStyle { + /** + * Length unit + * + * @const string + */ + const UNIT_PT = 'pt'; // Mostly for shapes + const UNIT_PX = 'px'; // Mostly for images + + /** + * Position type, relative/absolute + * + * @const string + */ + const POS_ABSOLUTE = 'absolute'; + const POS_RELATIVE = 'relative'; + + /** + * Horizontal/vertical value + * + * @const string + */ + const POS_CENTER = 'center'; + const POS_LEFT = 'left'; + const POS_RIGHT = 'right'; + const POS_TOP = 'top'; + const POS_BOTTOM = 'bottom'; + const POS_INSIDE = 'inside'; + const POS_OUTSIDE = 'outside'; + + /** + * Position relative to + * + * @const string + */ + const POS_RELTO_MARGIN = 'margin'; + const POS_RELTO_PAGE = 'page'; + const POS_RELTO_COLUMN = 'column'; // horizontal only + const POS_RELTO_CHAR = 'char'; // horizontal only + const POS_RELTO_TEXT = 'text'; // vertical only + const POS_RELTO_LINE = 'line'; // vertical only + const POS_RELTO_LMARGIN = 'left-margin-area'; // horizontal only + const POS_RELTO_RMARGIN = 'right-margin-area'; // horizontal only + const POS_RELTO_TMARGIN = 'top-margin-area'; // vertical only + const POS_RELTO_BMARGIN = 'bottom-margin-area'; // vertical only + const POS_RELTO_IMARGIN = 'inner-margin-area'; + const POS_RELTO_OMARGIN = 'outer-margin-area'; + + /** + * Wrap type + * + * @const string + */ + const WRAP_INLINE = 'inline'; + const WRAP_SQUARE = 'square'; + const WRAP_TIGHT = 'tight'; + const WRAP_THROUGH = 'through'; + const WRAP_TOPBOTTOM = 'topAndBottom'; + const WRAP_BEHIND = 'behind'; + const WRAP_INFRONT = 'infront'; + + /** + * Alignment + * + * @var \PhpOffice\PhpWord\Style\Alignment + */ + private $alignment; + + /** + * Unit + * + * @var string + */ + private $unit = 'pt'; + /** * Width * @@ -55,6 +129,48 @@ class Frame extends AbstractStyle */ private $top = 0; + /** + * Position type: absolute|relative + * + * @var string + */ + private $pos; + + /** + * Horizontal position + * + * @var string + */ + private $hPos; + + /** + * Horizontal position relative to + * + * @var string + */ + private $hPosRelTo; + + /** + * Vertical position + * + * @var string + */ + private $vPos; + + /** + * Vertical position relative to + * + * @var string + */ + private $vPosRelTo; + + /** + * Wrap type + * + * @var string + */ + private $wrap; + /** * Create a new instance * @@ -62,9 +178,56 @@ class Frame extends AbstractStyle */ public function __construct($style = array()) { + $this->alignment = new Alignment(); $this->setStyleByArray($style); } + /** + * Get alignment + * + * @return string + */ + public function getAlign() + { + return $this->alignment->getValue(); + } + + /** + * Set alignment + * + * @param string $value + * @return self + */ + public function setAlign($value = null) + { + $this->alignment->setValue($value); + + return $this; + } + + /** + * Get unit + * + * @return string + */ + public function getUnit() + { + return $this->unit; + } + + /** + * Set unit + * + * @param string $value + * @return self + */ + public function setUnit($value) + { + $this->unit = $value; + + return $this; + } + /** * Get width * @@ -156,4 +319,157 @@ class Frame extends AbstractStyle return $this; } + + /** + * Get position type + * + * @return string + */ + public function getPos() + { + return $this->pos; + } + + /** + * Set position type + * + * @param string $value + * @return self + */ + public function setPos($value) + { + $enum = array(self::POS_RELATIVE, self::POS_ABSOLUTE); + $this->pos = $this->setEnumVal($value, $enum, $this->pos); + + return $this; + } + + /** + * Get horizontal position + * + * @return string + */ + public function getHPos() + { + return $this->hPos; + } + + /** + * Set horizontal position + * + * @param string $value + * @return self + */ + public function setHPos($value) + { + $enum = array(self::POS_LEFT, self::POS_CENTER, self::POS_RIGHT, self::POS_INSIDE, self::POS_OUTSIDE); + $this->hPos = $this->setEnumVal($value, $enum, $this->hPos); + + return $this; + } + + /** + * Get vertical position + * + * @return string + */ + public function getVPos() + { + return $this->vPos; + } + + /** + * Set vertical position + * + * @param string $value + * @return self + */ + public function setVPos($value) + { + $enum = array(self::POS_TOP, self::POS_CENTER, self::POS_BOTTOM, self::POS_INSIDE, self::POS_OUTSIDE); + $this->vPos = $this->setEnumVal($value, $enum, $this->vPos); + + return $this; + } + + /** + * Get horizontal position relative to + * + * @return string + */ + public function getHPosRelTo() + { + return $this->hPosRelTo; + } + + /** + * Set horizontal position relative to + * + * @param string $value + * @return self + */ + public function setHPosRelTo($value) + { + $enum = array( + self::POS_RELTO_MARGIN, self::POS_RELTO_PAGE, self::POS_RELTO_COLUMN, self::POS_RELTO_CHAR, + self::POS_RELTO_LMARGIN, self::POS_RELTO_RMARGIN, self::POS_RELTO_IMARGIN, self::POS_RELTO_OMARGIN, + ); + $this->hPosRelTo = $this->setEnumVal($value, $enum, $this->hPosRelTo); + + return $this; + } + + /** + * Get vertical position relative to + * + * @return string + */ + public function getVPosRelTo() + { + return $this->vPosRelTo; + } + + /** + * Set vertical position relative to + * + * @param string $value + * @return self + */ + public function setVPosRelTo($value) + { + $enum = array( + self::POS_RELTO_MARGIN, self::POS_RELTO_PAGE, self::POS_RELTO_TEXT, self::POS_RELTO_LINE, + self::POS_RELTO_TMARGIN, self::POS_RELTO_BMARGIN, self::POS_RELTO_IMARGIN, self::POS_RELTO_OMARGIN, + ); + $this->vPosRelTo = $this->setEnumVal($value, $enum, $this->vPosRelTo); + + return $this; + } + + /** + * Get wrap type + * + * @return string + */ + public function getWrap() + { + return $this->wrap; + } + + /** + * Set wrap type + * + * @param string $value + * @return self + */ + public function setWrap($value) + { + $enum = array( + self::WRAP_INLINE, self::WRAP_SQUARE, self::WRAP_TIGHT, self::WRAP_THROUGH, + self::WRAP_TOPBOTTOM, self::WRAP_BEHIND, self::WRAP_INFRONT + ); + $this->wrap = $this->setEnumVal($value, $enum, $this->wrap); + + return $this; + } } diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 3798c1a2..babfa679 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -19,217 +19,56 @@ namespace PhpOffice\PhpWord\Style; /** * Image and memory image style */ -class Image extends AbstractStyle +class Image extends Frame { /** - * Wrapping styles + * Backward compatibility constants * * @const string */ - const WRAPPING_STYLE_INLINE = 'inline'; - const WRAPPING_STYLE_SQUARE = 'square'; - const WRAPPING_STYLE_TIGHT = 'tight'; - const WRAPPING_STYLE_BEHIND = 'behind'; - const WRAPPING_STYLE_INFRONT = 'infront'; - - /** - * Horizontal alignment - * - * @const string - */ - const POSITION_HORIZONTAL_LEFT = 'left'; - const POSITION_HORIZONTAL_CENTER = 'center'; - const POSITION_HORIZONTAL_RIGHT = 'right'; - - /** - * Vertical alignment - * - * @const string - */ - const POSITION_VERTICAL_TOP = 'top'; - const POSITION_VERTICAL_CENTER = 'center'; - const POSITION_VERTICAL_BOTTOM = 'bottom'; - const POSITION_VERTICAL_INSIDE = 'inside'; - const POSITION_VERTICAL_OUTSIDE = 'outside'; - - /** - * Position relative to - * - * @const string - */ - const POSITION_RELATIVE_TO_MARGIN = 'margin'; - const POSITION_RELATIVE_TO_PAGE = 'page'; - const POSITION_RELATIVE_TO_COLUMN = 'column'; // horizontal only - const POSITION_RELATIVE_TO_CHAR = 'char'; // horizontal only - const POSITION_RELATIVE_TO_TEXT = 'text'; // vertical only - const POSITION_RELATIVE_TO_LINE = 'line'; // vertical only - const POSITION_RELATIVE_TO_LMARGIN = 'left-margin-area'; // horizontal only - const POSITION_RELATIVE_TO_RMARGIN = 'right-margin-area'; // horizontal only - const POSITION_RELATIVE_TO_TMARGIN = 'top-margin-area'; // vertical only - const POSITION_RELATIVE_TO_BMARGIN = 'bottom-margin-area'; // vertical only - const POSITION_RELATIVE_TO_IMARGIN = 'inner-margin-area'; - const POSITION_RELATIVE_TO_OMARGIN = 'outer-margin-area'; - - /** - * Position type, relative/absolute - * - * @const string - */ - const POSITION_ABSOLUTE = 'absolute'; - const POSITION_RELATIVE = 'relative'; - - /** - * Image width - * - * @var int - */ - private $width; - - /** - * Image width - * - * @var int - */ - private $height; - - /** - * Alignment - * - * @var \PhpOffice\PhpWord\Style\Alignment - */ - private $alignment; - - /** - * Margin Top - * - * @var int|float - */ - private $marginTop = 0; - - /** - * Margin Left - * - * @var int|float - */ - private $marginLeft = 0; - - /** - * Wrapping style - * - * @var string - */ - private $wrappingStyle = self::WRAPPING_STYLE_INLINE; - - /** - * Positioning type (relative or absolute) - * - * @var string - */ - private $positioning; - - /** - * Horizontal alignment - * - * @var string - */ - private $posHorizontal = self::POSITION_HORIZONTAL_LEFT; - - /** - * Horizontal Relation - * - * @var string - */ - private $posHorizontalRel = self::POSITION_RELATIVE_TO_CHAR; - - /** - * Vertical alignment - * - * @var string - */ - private $posVertical = self::POSITION_VERTICAL_TOP; - - /** - * Vertical Relation - * - * @var string - */ - private $posVerticalRel = self::POSITION_RELATIVE_TO_LINE; + const WRAPPING_STYLE_INLINE = self::WRAP_INLINE; + const WRAPPING_STYLE_SQUARE = self::WRAP_SQUARE; + const WRAPPING_STYLE_TIGHT = self::WRAP_TIGHT; + const WRAPPING_STYLE_BEHIND = self::WRAP_BEHIND; + const WRAPPING_STYLE_INFRONT = self::WRAP_INFRONT; + const POSITION_HORIZONTAL_LEFT = self::POS_LEFT; + const POSITION_HORIZONTAL_CENTER = self::POS_CENTER; + const POSITION_HORIZONTAL_RIGHT = self::POS_RIGHT; + const POSITION_VERTICAL_TOP = self::POS_TOP; + const POSITION_VERTICAL_CENTER = self::POS_CENTER; + const POSITION_VERTICAL_BOTTOM = self::POS_BOTTOM; + const POSITION_VERTICAL_INSIDE = self::POS_INSIDE; + const POSITION_VERTICAL_OUTSIDE = self::POS_OUTSIDE; + const POSITION_RELATIVE_TO_MARGIN = self::POS_RELTO_MARGIN; + const POSITION_RELATIVE_TO_PAGE = self::POS_RELTO_PAGE; + const POSITION_RELATIVE_TO_COLUMN = self::POS_RELTO_COLUMN; + const POSITION_RELATIVE_TO_CHAR = self::POS_RELTO_CHAR; + const POSITION_RELATIVE_TO_TEXT = self::POS_RELTO_TEXT; + const POSITION_RELATIVE_TO_LINE = self::POS_RELTO_LINE; + const POSITION_RELATIVE_TO_LMARGIN = self::POS_RELTO_LMARGIN; + const POSITION_RELATIVE_TO_RMARGIN = self::POS_RELTO_RMARGIN; + const POSITION_RELATIVE_TO_TMARGIN = self::POS_RELTO_TMARGIN; + const POSITION_RELATIVE_TO_BMARGIN = self::POS_RELTO_BMARGIN; + const POSITION_RELATIVE_TO_IMARGIN = self::POS_RELTO_IMARGIN; + const POSITION_RELATIVE_TO_OMARGIN = self::POS_RELTO_OMARGIN; + const POSITION_ABSOLUTE = self::POS_ABSOLUTE; + const POSITION_RELATIVE = self::POS_RELATIVE; /** * Create new instance */ public function __construct() { - $this->alignment = new Alignment(); - } + parent::__construct(); + $this->setUnit('px'); - /** - * Get width - * - * @return int - */ - public function getWidth() - { - return $this->width; - } - - /** - * Set width - * - * @param int $value - * @return self - */ - public function setWidth($value = null) - { - $this->width = $value; - - return $this; - } - - /** - * Get height - * - * @return int - */ - public function getHeight() - { - return $this->height; - } - - /** - * Set height - * - * @param int $value - * @return self - */ - public function setHeight($value = null) - { - $this->height = $value; - - return $this; - } - - /** - * Get alignment - * - * @return string - */ - public function getAlign() - { - return $this->alignment->getValue(); - } - - /** - * Set alignment - * - * @param string $value - * @return self - */ - public function setAlign($value = null) - { - $this->alignment->setValue($value); - - return $this; + // Backward compatilibity setting + // @todo Remove on 1.0.0 + $this->setWrap(self::WRAPPING_STYLE_INLINE); + $this->setHPos(self::POSITION_HORIZONTAL_LEFT); + $this->setHPosRelTo(self::POSITION_RELATIVE_TO_CHAR); + $this->setVPos(self::POSITION_VERTICAL_TOP); + $this->setVPosRelTo(self::POSITION_RELATIVE_TO_LINE); } /** @@ -239,7 +78,7 @@ class Image extends AbstractStyle */ public function getMarginTop() { - return $this->marginTop; + return $this->getTop(); } /** @@ -251,7 +90,7 @@ class Image extends AbstractStyle */ public function setMarginTop($value = 0) { - $this->marginTop = $this->setNumericVal($value, 0); + $this->setTop($value); return $this; } @@ -263,7 +102,7 @@ class Image extends AbstractStyle */ public function getMarginLeft() { - return $this->marginLeft; + return $this->getLeft(); } /** @@ -275,7 +114,7 @@ class Image extends AbstractStyle */ public function setMarginLeft($value = 0) { - $this->marginLeft = $this->setNumericVal($value, 0); + $this->setLeft($value); return $this; } @@ -287,7 +126,7 @@ class Image extends AbstractStyle */ public function getWrappingStyle() { - return $this->wrappingStyle; + return $this->getWrap(); } /** @@ -299,12 +138,7 @@ class Image extends AbstractStyle */ public function setWrappingStyle($wrappingStyle) { - $enum = array( - self::WRAPPING_STYLE_INLINE, - self::WRAPPING_STYLE_INFRONT, self::WRAPPING_STYLE_BEHIND, - self::WRAPPING_STYLE_SQUARE, self::WRAPPING_STYLE_TIGHT, - ); - $this->wrappingStyle = $this->setEnumVal($wrappingStyle, $enum, $this->wrappingStyle); + $this->setWrap($wrappingStyle); return $this; } @@ -316,7 +150,7 @@ class Image extends AbstractStyle */ public function getPositioning() { - return $this->positioning; + return $this->getPos(); } /** @@ -328,8 +162,7 @@ class Image extends AbstractStyle */ public function setPositioning($positioning) { - $enum = array(self::POSITION_RELATIVE, self::POSITION_ABSOLUTE); - $this->positioning = $this->setEnumVal($positioning, $enum, $this->positioning); + $this->setPos($positioning); return $this; } @@ -341,7 +174,7 @@ class Image extends AbstractStyle */ public function getPosHorizontal() { - return $this->posHorizontal; + return $this->getHPos(); } /** @@ -353,11 +186,7 @@ class Image extends AbstractStyle */ public function setPosHorizontal($alignment) { - $enum = array( - self::POSITION_HORIZONTAL_LEFT, self::POSITION_HORIZONTAL_CENTER, - self::POSITION_HORIZONTAL_RIGHT, self::POSITION_ABSOLUTE - ); - $this->posHorizontal = $this->setEnumVal($alignment, $enum, $this->posHorizontal); + $this->setHPos($alignment); return $this; } @@ -369,7 +198,7 @@ class Image extends AbstractStyle */ public function getPosVertical() { - return $this->posVertical; + return $this->getVPos(); } /** @@ -381,12 +210,7 @@ class Image extends AbstractStyle */ public function setPosVertical($alignment) { - $enum = array( - self::POSITION_VERTICAL_TOP, self::POSITION_VERTICAL_CENTER, - self::POSITION_VERTICAL_BOTTOM, self::POSITION_VERTICAL_INSIDE, - self::POSITION_VERTICAL_OUTSIDE, self::POSITION_ABSOLUTE - ); - $this->posVertical = $this->setEnumVal($alignment, $enum, $this->posVertical); + $this->setVPos($alignment); return $this; } @@ -398,7 +222,7 @@ class Image extends AbstractStyle */ public function getPosHorizontalRel() { - return $this->posHorizontalRel; + return $this->getHPosRelTo(); } /** @@ -410,13 +234,7 @@ class Image extends AbstractStyle */ public function setPosHorizontalRel($relto) { - $enum = array( - self::POSITION_RELATIVE_TO_MARGIN, self::POSITION_RELATIVE_TO_PAGE, - self::POSITION_RELATIVE_TO_COLUMN, self::POSITION_RELATIVE_TO_CHAR, - self::POSITION_RELATIVE_TO_LMARGIN, self::POSITION_RELATIVE_TO_RMARGIN, - self::POSITION_RELATIVE_TO_IMARGIN, self::POSITION_RELATIVE_TO_OMARGIN, - ); - $this->posHorizontalRel = $this->setEnumVal($relto, $enum, $this->posHorizontalRel); + $this->setHPosRelTo($relto); return $this; } @@ -428,7 +246,7 @@ class Image extends AbstractStyle */ public function getPosVerticalRel() { - return $this->posVerticalRel; + return $this->getVPosRelTo(); } /** @@ -440,13 +258,7 @@ class Image extends AbstractStyle */ public function setPosVerticalRel($relto) { - $enum = array( - self::POSITION_RELATIVE_TO_MARGIN, self::POSITION_RELATIVE_TO_PAGE, - self::POSITION_RELATIVE_TO_TEXT, self::POSITION_RELATIVE_TO_LINE, - self::POSITION_RELATIVE_TO_TMARGIN, self::POSITION_RELATIVE_TO_BMARGIN, - self::POSITION_RELATIVE_TO_IMARGIN, self::POSITION_RELATIVE_TO_OMARGIN, - ); - $this->posVerticalRel = $this->setEnumVal($relto, $enum, $this->posVerticalRel); + $this->setVPosRelTo($relto); return $this; } diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index 7e6b19cf..bfd14a14 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -21,6 +21,7 @@ namespace PhpOffice\PhpWord\Style; * Outline defines the line/border of the object * * @link http://www.schemacentral.com/sc/ooxml/t-v_CT_Stroke.html + * @link http://www.w3.org/TR/1998/NOTE-VML-19980513#_Toc416858395 * @since 0.12.0 */ class Outline extends AbstractStyle @@ -37,6 +38,16 @@ class Outline extends AbstractStyle const LINE_THICK_THIN = 'thickThin'; const LINE_THICK_BETWEEN_THIN = 'thickBetweenThin'; + /** + * Line style constants + * + * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + * @const string + */ + const ENDCAP_FLAT = 'flat'; + const ENDCAP_SQUARE = 'square'; + const ENDCAP_ROUND = 'round'; + /** * Arrowhead type constants * @@ -50,6 +61,13 @@ class Outline extends AbstractStyle const ARROW_DIAMOND = 'diamond'; const ARROW_OPEN = 'open'; + /** + * Unit; No set method for now + * + * @var string + */ + private $unit = 'pt'; + /** * Outline weight * @@ -78,6 +96,14 @@ class Outline extends AbstractStyle */ private $line; + /** + * End cap + * + * @var string + * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + */ + private $endCap; + /** * Start arrow type * @@ -102,6 +128,16 @@ class Outline extends AbstractStyle $this->setStyleByArray($style); } + /** + * Get unit + * + * @return string + */ + public function getUnit() + { + return $this->unit; + } + /** * Get weight * @@ -196,6 +232,30 @@ class Outline extends AbstractStyle return $this; } + /** + * Get endCap style + * + * @return string + */ + public function getEndCap() + { + return $this->endCap; + } + + /** + * Set endCap style + * + * @param string $value + * @return self + */ + public function setEndCap($value = null) + { + $enum = array(self::ENDCAP_FLAT, self::ENDCAP_SQUARE, self::ENDCAP_ROUND); + $this->endCap = $this->setEnumVal($value, $enum, null); + + return $this; + } + /** * Get startArrow * diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 963e2da1..02780ed1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -52,7 +52,6 @@ class Image extends AbstractElement private function writeImage(XMLWriter $xmlWriter, ImageElement $element) { $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0); - $style = $element->getStyle(); $styleWriter = new ImageStyleWriter($xmlWriter, $style); @@ -67,7 +66,6 @@ class Image extends AbstractElement $xmlWriter->writeAttribute('type', '#_x0000_t75'); $styleWriter->write(); - $styleWriter->writeW10Wrap(); $xmlWriter->startElement('v:imagedata'); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); @@ -78,7 +76,7 @@ class Image extends AbstractElement $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - $this->endElementP(); // w:p + $this->endElementP(); } /** * Write watermark element @@ -86,29 +84,25 @@ class Image extends AbstractElement private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) { $rId = $element->getRelationId(); - $style = $element->getStyle(); + $style->setPositioning('absolute'); $styleWriter = new ImageStyleWriter($xmlWriter, $style); $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t75'); - $style->setPositioning('absolute'); $styleWriter->write(); $xmlWriter->startElement('v:imagedata'); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->writeAttribute('o:title', ''); $xmlWriter->endElement(); // v:imagedata - $xmlWriter->endElement(); // v:shape $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index ce576030..ade5b889 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -76,7 +76,6 @@ class Line extends AbstractElement $xmlWriter->writeAttribute('type', '#_x0000_t32'); //type should correspond to shapetype id $styleWriter->write(); - $styleWriter->writeW10Wrap(); $styleWriter->writeStroke(); $xmlWriter->endElement(); // v:shape diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 00fac58e..71935d6e 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -24,7 +24,7 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\TextBox as TextBoxStyleWriter; * * @since 0.11.0 */ -class TextBox extends AbstractElement +class TextBox extends Image { /** * Write element @@ -36,7 +36,6 @@ class TextBox extends AbstractElement if (!$element instanceof \PhpOffice\PhpWord\Element\TextBox) { return; } - $style = $element->getStyle(); $styleWriter = new TextBoxStyleWriter($xmlWriter, $style); @@ -51,6 +50,7 @@ class TextBox extends AbstractElement $xmlWriter->writeAttribute('type', '#_x0000_t0202'); $styleWriter->write(); + $styleWriter->writeBorder(); $xmlWriter->startElement('v:textbox'); $styleWriter->writeInnerMargin(); @@ -62,11 +62,11 @@ class TextBox extends AbstractElement $xmlWriter->endElement(); // w:txbxContent $xmlWriter->endElement(); // v: textbox - $styleWriter->writeW10Wrap(); + $xmlWriter->endElement(); // v:shape $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - $this->endElementP(); // w:p + $this->endElementP(); } } diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index dd2337ee..507c0c02 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -17,6 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; +use PhpOffice\PhpWord\Style\Frame as FrameStyle; + /** * Frame style writer * @@ -30,27 +34,122 @@ class Frame extends AbstractStyle public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Frame) { + if (!$style instanceof FrameStyle) { return; } $xmlWriter = $this->getXmlWriter(); - $styles = array(); + $zIndices = array(FrameStyle::WRAP_INFRONT => PHP_INT_MAX, FrameStyle::WRAP_BEHIND => -PHP_INT_MAX); + $properties = array( - 'left' => 'margin-left', - 'top' => 'margin-top', - 'width' => 'width', - 'height' => 'height', + 'width' => 'width', + 'height' => 'height', + 'left' => 'margin-left', + 'top' => 'margin-top', ); + $sizeStyles = $this->getStyles($style, $properties, $style->getUnit()); + + $properties = array( + 'pos' => 'position', + 'hPos' => 'mso-position-horizontal', + 'vPos' => 'mso-position-vertical', + 'hPosRelTo' => 'mso-position-horizontal-relative', + 'vPosRelTo' => 'mso-position-vertical-relative', + ); + $posStyles = $this->getStyles($style, $properties); + + $styles = array_merge($sizeStyles, $posStyles); + + // zIndex for infront & behind wrap + $wrap = $style->getWrap(); + if ($wrap !== null && array_key_exists($wrap, $zIndices)) { + $styles['z-index'] = $zIndices[$wrap]; + $wrap = null; + } + + // Style attribute + $xmlWriter->writeAttribute('style', $this->assembleStyle($styles)); + + $this->writeWrap($xmlWriter, $style, $wrap); + } + + /** + * Write alignment + */ + public function writeAlignment() + { + $style = $this->getStyle(); + if (!$style instanceof FrameStyle) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:pPr'); + $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); + $styleWriter->write(); + $xmlWriter->endElement(); // w:pPr + } + + /** + * Write alignment + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Frame $style + * @param string $wrap + */ + private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap) + { + if ($wrap !== null) { + $xmlWriter->startElement('w10:wrap'); + $xmlWriter->writeAttribute('type', $wrap); + + $relativePositions = array( + FrameStyle::POS_RELTO_MARGIN => 'margin', + FrameStyle::POS_RELTO_PAGE => 'page', + FrameStyle::POS_RELTO_TMARGIN => 'margin', + FrameStyle::POS_RELTO_BMARGIN => 'page', + FrameStyle::POS_RELTO_LMARGIN => 'margin', + FrameStyle::POS_RELTO_RMARGIN => 'page', + ); + $pos = $style->getPos(); + $hPos = $style->getHPosRelTo(); + $vPos = $style->getVPosRelTo(); + + if ($pos == FrameStyle::POS_ABSOLUTE) { + $xmlWriter->writeAttribute('anchorx', "page"); + $xmlWriter->writeAttribute('anchory', "page"); + } elseif ($pos == FrameStyle::POS_RELATIVE) { + if (array_key_exists($hPos, $relativePositions)) { + $xmlWriter->writeAttribute('anchorx', $relativePositions[$hPos]); + } + if (array_key_exists($vPos, $relativePositions)) { + $xmlWriter->writeAttribute('anchory', $relativePositions[$vPos]); + } + } + + $xmlWriter->endElement(); // w10:wrap + } + } + + /** + * Get style values in associative array + * + * @param array $properties + * @param string $suffix + * @return array + */ + private function getStyles(FrameStyle $style, $properties, $suffix = '') + { + $styles = array(); foreach ($properties as $key => $property) { $method = "get{$key}"; $value = $style->$method(); if ($value !== null) { - $styles[$property] = $style->$method() . 'pt'; + $styles[$property] = $style->$method() . $suffix; } } - $xmlWriter->writeAttribute('style', $this->assembleStyle($styles)); + return $styles; } } diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index aebc93c1..cabf37ce 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -17,139 +17,11 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; -use PhpOffice\PhpWord\Style\Image as ImageStyle; - /** * Image style writer * * @since 0.10.0 */ -class Image extends AbstractStyle +class Image extends Frame { - /** - * w10 namespace wrapping type - * - * @var string - */ - protected $w10wrap; - - /** - * Write style - */ - public function write() - { - $style = $this->getStyle(); - if (!$style instanceof ImageStyle) { - return; - } - $this->writeStyle($style); - } - - /** - * Write style attribute - * - * @param \PhpOffice\PhpWord\Style\Image $style - */ - protected function writeStyle($style) - { - $xmlWriter = $this->getXmlWriter(); - - $styles = $this->getElementStyle($style); - $imageStyle = $this->assembleStyle($styles); - - $xmlWriter->writeAttribute('style', $imageStyle); - } - - /** - * Write alignment - */ - public function writeAlignment() - { - $style = $this->getStyle(); - if (!$style instanceof ImageStyle) { - return; - } - - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w:pPr'); - $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); - $styleWriter->write(); - $xmlWriter->endElement(); // w:pPr - } - - /** - * Write w10 wrapping - */ - public function writeW10Wrap() - { - if (is_null($this->w10wrap)) { - return; - } - - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w10:wrap'); - $xmlWriter->writeAttribute('type', $this->w10wrap); - $xmlWriter->endElement(); // w10:wrap - } - - /** - * Get element style - * - * @param \PhpOffice\PhpWord\Style\Image $style - * @return array - */ - protected function getElementStyle(ImageStyle $style) - { - $styles = array( - 'mso-width-percent' => '0', - 'mso-height-percent' => '0', - 'mso-width-relative' => 'margin', - 'mso-height-relative' => 'margin', - ); - - // Dimension - $dimensions = array( - 'width' => $style->getWidth(), - 'height' => $style->getHeight(), - 'margin-top' => $style->getMarginTop(), - 'margin-left' => $style->getMarginLeft() - ); - foreach ($dimensions as $key => $value) { - if ($value !== null) { - $styles[$key] = $value . 'px'; - } - } - - // Absolute/relative positioning - $positioning = $style->getPositioning(); - $styles['position'] = $positioning; - if ($positioning !== null) { - $styles['mso-position-horizontal'] = $style->getPosHorizontal(); - $styles['mso-position-vertical'] = $style->getPosVertical(); - $styles['mso-position-horizontal-relative'] = $style->getPosHorizontalRel(); - $styles['mso-position-vertical-relative'] = $style->getPosVerticalRel(); - } - - // Wrapping style - $wrapping = $style->getWrappingStyle(); - if ($wrapping == ImageStyle::WRAPPING_STYLE_INLINE) { - // Nothing to do when inline - } elseif ($wrapping == ImageStyle::WRAPPING_STYLE_BEHIND) { - $styles['z-index'] = -251658752; - } else { - $styles['z-index'] = 251659264; - $styles['mso-position-horizontal'] = 'absolute'; - $styles['mso-position-vertical'] = 'absolute'; - } - - // w10 wrapping - if ($wrapping == ImageStyle::WRAPPING_STYLE_SQUARE) { - $this->w10wrap = 'square'; - } elseif ($wrapping == ImageStyle::WRAPPING_STYLE_TIGHT) { - $this->w10wrap = 'tight'; - } - - return $styles; - } } diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index dfecb4b0..8a56cb7b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -23,50 +23,12 @@ use PhpOffice\PhpWord\Style\Line as LineStyle; * Line style writer * */ -class Line extends Image +class Line extends Frame { - /** - * Write style - */ - public function write() - { - $style = $this->getStyle(); - if (!$style instanceof LineStyle) { - return; - } - $this->writeStyle($style); - } - - /** - * Write style attribute - * - * @param \PhpOffice\PhpWord\Style\Line $style - */ - protected function writeStyle($style) - { - $xmlWriter = $this->getXmlWriter(); - - $styles = $this->getElementStyle($style); - if ($style->isFlip()) { - $styles['flip'] = 'y'; - } - $imageStyle = $this->assembleStyle($styles); - $xmlWriter->writeAttribute('style', $imageStyle); - - // Connector type - $xmlWriter->writeAttribute('o:connectortype', $style->getConnectorType()); - - // Weight - $weight = $style->getWeight(); - $xmlWriter->writeAttributeIf($weight !== null, 'strokeweight', $weight . 'pt'); - - // Color - $color = $style->getColor(); - $xmlWriter->writeAttributeIf($color !== null, 'strokecolor', $color); - } - /** * Write Line stroke + * + * @todo Merge with `Stroke` style */ public function writeStroke() { @@ -77,8 +39,6 @@ class Line extends Image } $dash = $style->getDash(); - $beginArrow = $style->getBeginArrow(); - $endArrow = $style->getEndArrow(); $dashStyles = array( LineStyle::DASH_STYLE_DASH => 'dash', LineStyle::DASH_STYLE_ROUND_DOT => '1 1', @@ -89,22 +49,22 @@ class Line extends Image LineStyle::DASH_STYLE_LONG_DASH_DOT_DOT => 'longDashDotDot', ); - if (($dash !== null) || ($beginArrow !== null) || ($endArrow !== null)) { - $xmlWriter->startElement('v:stroke'); + $xmlWriter->startElement('v:stroke'); - $xmlWriter->writeAttributeIf($beginArrow !== null, 'startarrow', $beginArrow); - $xmlWriter->writeAttributeIf($endArrow !== null, 'endarrow', $endArrow); + $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . 'pt'); + $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); + $xmlWriter->writeAttributeIf($style->getBeginArrow() !== null, 'startarrow', $style->getBeginArrow()); + $xmlWriter->writeAttributeIf($style->getEndArrow() !== null, 'endarrow', $style->getEndArrow()); - if ($dash !== null) { - if (array_key_exists($dash, $dashStyles)) { - $xmlWriter->writeAttribute('dashstyle', $dashStyles[$dash]); - } - if ($dash == LineStyle::DASH_STYLE_ROUND_DOT) { - $xmlWriter->writeAttribute('endcap', 'round'); - } + if ($dash !== null) { + if (array_key_exists($dash, $dashStyles)) { + $xmlWriter->writeAttribute('dashstyle', $dashStyles[$dash]); + } + if ($dash == LineStyle::DASH_STYLE_ROUND_DOT) { + $xmlWriter->writeAttribute('endcap', 'round'); } - - $xmlWriter->endElement(); //v:stroke } + + $xmlWriter->endElement(); //v:stroke } } diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index 5003d9fc..e53282a3 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -38,9 +38,10 @@ class Outline extends AbstractStyle $xmlWriter->startElement("v:stroke"); $xmlWriter->writeAttribute('on', 't'); $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); - $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . 'pt'); + $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . $style->getUnit()); $xmlWriter->writeAttributeIf($style->getDash() !== null, 'dashstyle', $style->getDash()); $xmlWriter->writeAttributeIf($style->getLine() !== null, 'linestyle', $style->getLine()); + $xmlWriter->writeAttributeIf($style->getEndCap() !== null, 'endcap', $style->getEndCap()); $xmlWriter->writeAttributeIf($style->getStartArrow() !== null, 'startarrow', $style->getStartArrow()); $xmlWriter->writeAttributeIf($style->getEndArrow() !== null, 'endarrow', $style->getEndArrow()); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 13f40256..a5f82e53 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -24,67 +24,8 @@ use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; * * @since 0.11.0 */ -class TextBox extends Image +class TextBox extends Frame { - /** - * Write style - */ - public function write() - { - $style = $this->getStyle(); - if (!$style instanceof TextBoxStyle) { - return; - } - $this->writeStyle($style); - $this->writeBorder($style); - } - - /** - * Write w10 wrapping - * - * @return array - */ - public function writeW10Wrap() - { - if (is_null($this->w10wrap)) { - return; - } - $style = $this->getStyle(); - if (!$style instanceof TextBoxStyle) { - return; - } - - $relativePositions = array( - TextBoxStyle::POSITION_RELATIVE_TO_MARGIN => 'margin', - TextBoxStyle::POSITION_RELATIVE_TO_PAGE => 'page', - TextBoxStyle::POSITION_RELATIVE_TO_TMARGIN => 'margin', - TextBoxStyle::POSITION_RELATIVE_TO_BMARGIN => 'page', - TextBoxStyle::POSITION_RELATIVE_TO_LMARGIN => 'margin', - TextBoxStyle::POSITION_RELATIVE_TO_RMARGIN => 'page', - ); - $pos = $style->getPositioning(); - $vPos = $style->getPosVerticalRel(); - $hPos = $style->getPosHorizontalRel(); - - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w10:wrap'); - $xmlWriter->writeAttribute('type', $this->w10wrap); - - if ($pos == TextBoxStyle::POSITION_ABSOLUTE) { - $xmlWriter->writeAttribute('anchorx', "page"); - $xmlWriter->writeAttribute('anchory', "page"); - } elseif ($pos == TextBoxStyle::POSITION_RELATIVE) { - if (array_key_exists($vPos, $relativePositions)) { - $xmlWriter->writeAttribute('anchory', $relativePositions[$vPos]); - } - if (array_key_exists($hPos, $relativePositions)) { - $xmlWriter->writeAttribute('anchorx', $relativePositions[$hPos]); - } - } - - $xmlWriter->endElement(); // w10:wrap - } - /** * Writer inner margin */ @@ -97,29 +38,24 @@ class TextBox extends Image $xmlWriter = $this->getXmlWriter(); $margins = implode(', ', $style->getInnerMargin()); + $xmlWriter->writeAttribute('inset', $margins); } /** * Writer border */ - private function writeBorder(TextBoxStyle $style) + public function writeBorder() { + $style = $this->getStyle(); + if (!$style instanceof TextBoxStyle) { + return; + } $xmlWriter = $this->getXmlWriter(); - // Border size - $borderSize = $style->getBorderSize(); - if ($borderSize !== null) { - $xmlWriter->writeAttribute('strokeweight', $borderSize . 'pt'); - } - - // Border color - $borderColor = $style->getBorderColor(); - if (empty($borderColor)) { - $xmlWriter->writeAttribute('stroked', 'f'); - } else { - $xmlWriter->writeAttribute('strokecolor', $borderColor); - } - //@todo + $xmlWriter->startElement('v:stroke'); + $xmlWriter->writeAttributeIf($style->getBorderSize() !== null, 'weight', $style->getBorderSize() . 'pt'); + $xmlWriter->writeAttributeIf($style->getBorderColor() !== null, 'color', $style->getBorderColor()); + $xmlWriter->endElement(); // v:stroke } } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 9e74af2f..c21ea4ce 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -46,6 +46,7 @@ class FontTest extends \PHPUnit_Framework_TestCase $this->assertEquals('text', $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); + $this->assertTrue(is_array($object->getStyleValues())); } /** diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 6ba3477b..c774e9f3 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -103,7 +103,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase array( 'points' => '1,1 150,30', 'outline' => array('color' => '#cc00ff', 'line' => 'thickThin', 'weight' => 3, - 'startArrow' => 'oval', 'endArrow' => 'classic'), + 'startArrow' => 'oval', 'endArrow' => 'classic', 'endCap' => 'round'), ) ); diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php index c840d207..8dd229c3 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php @@ -49,8 +49,9 @@ class StyleTest extends \PHPUnit_Framework_TestCase public function testMethodExceptions() { $styles = array( - 'Image' => 'writeAlignment', - 'Line' => 'writeStroke', + 'Frame' => 'writeAlignment', + 'Line' => 'writeStroke', + 'TextBox' => 'writeBorder', ); foreach ($styles as $style => $method) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style; From f44ff4b7a6b6e618f9a21a0b893e95532562a0cd Mon Sep 17 00:00:00 2001 From: lrobert Date: Thu, 5 Jun 2014 10:47:53 -0400 Subject: [PATCH 242/326] Added shading to the paragraph style for full width shading --- src/PhpWord/Style/Paragraph.php | 31 +++++++++++++++++++ .../Writer/Word2007/Style/Paragraph.php | 7 +++++ 2 files changed, 38 insertions(+) diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 81673586..ef966635 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -152,6 +152,13 @@ class Paragraph extends AbstractStyle */ private $tabs = array(); + /** + * Shading + * + * @var \PhpOffice\PhpWord\Style\Shading + */ + private $shading; + /** * Create new instance */ @@ -209,6 +216,7 @@ class Paragraph extends AbstractStyle 'level' => $this->getNumLevel(), ), 'tabs' => $this->getTabs(), + 'shading' => $this->getShading(), ); return $styles; @@ -694,4 +702,27 @@ class Paragraph extends AbstractStyle { return $this->hasPageBreakBefore(); } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Shading + */ + public function getShading() + { + return $this->shading; + } + + /** + * Set shading + * + * @param mixed $value + * @return self + */ + public function setShading($value = null) + { + $this->setObjectVal($value, 'Shading', $this->shading); + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index f3287700..71bb6e48 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -99,6 +99,13 @@ class Paragraph extends AbstractStyle $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); + // Background-Color + $shading = $style->getShading(); + if (!is_null($shading)) { + $styleWriter = new Shading($xmlWriter, $shading); + $styleWriter->write(); + } + // Tabs $this->writeTabs($xmlWriter, $styles['tabs']); From 479713da5593f8e23071007195680a9f19cf6068 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 5 Jun 2014 22:41:58 +0700 Subject: [PATCH 243/326] Update changelog and unit test for #264 --- CHANGELOG.md | 1 + src/PhpWord/Writer/Word2007/Style/Paragraph.php | 10 ++-------- .../Tests/Writer/Word2007/Part/DocumentTest.php | 6 +++++- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 316f92bf..19d22c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin GH-123 - Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin +- Paragraph: Added shading to the paragraph style for full width shading - @lrobert GH-264 ### Bugfixes diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 7be537cd..4ccba00f 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -95,16 +95,10 @@ class Paragraph extends AbstractStyle $xmlWriter->writeElementIf($styles['pagination']['keepLines'] === true, 'w:keepLines', 'w:val', '1'); $xmlWriter->writeElementIf($styles['pagination']['pageBreak'] === true, 'w:pageBreakBefore', 'w:val', '1'); - // Indentation & spacing + // Child style: indentation, spacing, and shading $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); - - // Background-Color - $shading = $style->getShading(); - if (!is_null($shading)) { - $styleWriter = new Shading($xmlWriter, $shading); - $styleWriter->write(); - } + $this->writeChildStyle($xmlWriter, 'Shading', $styles['shading']); // Tabs $this->writeTabs($xmlWriter, $styles['tabs']); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 5e0dc747..fd36db25 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -135,7 +135,11 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $tabs = array(new \PhpOffice\PhpWord\Style\Tab('right', 9090)); $phpWord = new PhpWord(); - $phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'tabs' => $tabs)); // Style #1 + $phpWord->addParagraphStyle('pStyle', array( + 'align' => 'center', + 'tabs' => $tabs, + 'shading' => array('fill' => 'FFFF99'), + )); // Style #1 $phpWord->addFontStyle('fStyle', array('size' => '20', 'bold' => true, 'allCaps' => true, 'scale' => 200, 'spacing' => 240, 'kerning' => 10)); // Style #2 $phpWord->addTitleStyle(1, array('color' => '333333', 'doubleStrikethrough' => true)); // Style #3 From d97602fa98cd6ab0bc1bfb88c25a5b6d19aa6213 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 5 Jun 2014 23:47:39 +0700 Subject: [PATCH 244/326] Reduce duplications and fix some docblocks --- src/PhpWord/Element/AbstractContainer.php | 1 + src/PhpWord/Writer/RTF/Element/Table.php | 3 + .../Word2007/Element/AbstractElement.php | 61 ++++++++++++++++++- .../Writer/Word2007/Element/CheckBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/Field.php | 3 +- .../Writer/Word2007/Element/Footnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- .../Writer/Word2007/Element/PageBreak.php | 2 +- .../Writer/Word2007/Element/PreserveText.php | 2 +- src/PhpWord/Writer/Word2007/Element/Text.php | 60 +----------------- .../Writer/Word2007/Element/TextBreak.php | 2 +- .../Writer/Word2007/Element/TextRun.php | 2 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 1 + 13 files changed, 75 insertions(+), 68 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index ae750de9..7afdbb47 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -188,6 +188,7 @@ abstract class AbstractContainer extends AbstractElement /** * Set relation Id * + * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param string $elementName * @param string $source */ diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index b48e084f..7c4329f7 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -66,6 +66,7 @@ class Table extends AbstractElement /** * Write column * + * @param \PhpOffice\PhpWord\Element\Row $row * @return string */ private function writeRowDef(RowElement $row) @@ -89,6 +90,7 @@ class Table extends AbstractElement /** * Write row * + * @param \PhpOffice\PhpWord\Element\Row $row * @return string */ private function writeRow(RowElement $row) @@ -106,6 +108,7 @@ class Table extends AbstractElement /** * Write cell * + * @param \PhpOffice\PhpWord\Element\Cell $cell * @return string */ private function writeCell(CellElement $cell) diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index c1e721ed..e17640c8 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Element\AbstractElement as Element; +use PhpOffice\PhpWord\Element\PageBreak as PageBreakElement; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; @@ -116,7 +117,28 @@ abstract class AbstractElement } /** - * Write ending + * Start w:p DOM element + * + * @uses \PhpOffice\PhpWord\Writer\Word2007\Element\PageBreak::write() + */ + protected function startElementP() + { + if (!$this->withoutP) { + $this->xmlWriter->startElement('w:p'); + // Paragraph style + if (method_exists($this->element, 'getParagraphStyle')) { + $this->writeParagraphStyle(); + } + // PageBreak + if ($this->pageBreakBefore) { + $elementWriter = new PageBreak($this->xmlWriter, new PageBreakElement()); + $elementWriter->write(); + } + } + } + + /** + * End w:p DOM element */ protected function endElementP() { @@ -125,6 +147,43 @@ abstract class AbstractElement } } + /** + * Write ending + */ + protected function writeParagraphStyle() + { + $this->writeTextStyle('Paragraph'); + } + + /** + * Write ending + */ + protected function writeFontStyle() + { + $this->writeTextStyle('Font'); + } + + + /** + * Write text style + * + * @param string $styleType Font|Paragraph + */ + private function writeTextStyle($styleType) + { + $method = "get{$styleType}Style"; + $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\{$styleType}"; + $styleObject = $this->element->$method(); + + $styleWriter = new $class($this->xmlWriter, $styleObject); + if (method_exists($styleWriter, 'setIsInline')) { + $styleWriter->setIsInline(true); + } + + /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $styleWriter */ + $styleWriter->write(); + } + /** * Convert text to valid format * diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 2d0fe691..d5f6a64e 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -35,7 +35,7 @@ class CheckBox extends Text return; } - $this->writeOpeningWP(); + $this->startElementP(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 1e538e1a..7133e83f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -67,7 +67,8 @@ class Field extends Text } } - $this->writeOpeningWP(); + $this->startElementP(); + $xmlWriter->startElement('w:fldSimple'); $xmlWriter->writeAttribute('w:instr', $instruction); $xmlWriter->startElement('w:r'); diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 05b96ae5..be5a21f1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -42,7 +42,7 @@ class Footnote extends Text return; } - $this->writeOpeningWP(); + $this->startElementP(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:rPr'); diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 68851ec4..d7e68ac1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -37,7 +37,7 @@ class Link extends Text $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0); - $this->writeOpeningWP(); + $this->startElementP(); $xmlWriter->startElement('w:hyperlink'); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index 6974777a..47f3feb5 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -30,7 +30,7 @@ class PageBreak extends AbstractElement /** * Write element * - * @usedby \PhpOffice\PhpWord\Writer\Word2007\Element\Text::writeOpeningWP() + * @usedby \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement::startElementP() */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index c63d13a7..ef5b93cd 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -40,7 +40,7 @@ class PreserveText extends Text $texts = array($texts); } - $this->writeOpeningWP(); + $this->startElementP(); foreach ($texts as $text) { if (substr($text, 0, 1) == '{') { diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 5d92b3f9..1fa4861f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -17,10 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Element\PageBreak as PageBreakElement; -use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; -use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; - /** * Text element writer * @@ -39,7 +35,7 @@ class Text extends AbstractElement return; } - $this->writeOpeningWP(); + $this->startElementP(); $xmlWriter->startElement('w:r'); @@ -53,58 +49,4 @@ class Text extends AbstractElement $this->endElementP(); // w:p } - - /** - * Write opening - * - * @uses \PhpOffice\PhpWord\Writer\Word2007\Element\PageBreak::write() - */ - protected function writeOpeningWP() - { - $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); - - if (!$this->withoutP) { - $xmlWriter->startElement('w:p'); - // Paragraph style - if (method_exists($element, 'getParagraphStyle')) { - $this->writeParagraphStyle(); - } - // PageBreak - if ($this->hasPageBreakBefore()) { - $elementWriter = new PageBreak($xmlWriter, new PageBreakElement()); - $elementWriter->write(); - } - } - } - - /** - * Write ending - */ - protected function writeParagraphStyle() - { - $xmlWriter = $this->getXmlWriter(); - - /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ - $element = $this->getElement(); - $paragraphStyle = $element->getParagraphStyle(); - $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle); - $styleWriter->setIsInline(true); - $styleWriter->write(); - } - - /** - * Write ending - */ - protected function writeFontStyle() - { - $xmlWriter = $this->getXmlWriter(); - - /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ - $element = $this->getElement(); - $fontStyle = $element->getFontStyle(); - $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle); - $styleWriter->setIsInline(true); - $styleWriter->write(); - } } diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 2995e8be..83ec2221 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -37,7 +37,7 @@ class TextBreak extends Text if (!$this->withoutP) { $hasStyle = $element->hasStyle(); - $this->writeOpeningWP(); + $this->startElementP(); if ($hasStyle) { $xmlWriter->startElement('w:pPr'); diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index ca3a6b05..9ff348cf 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -32,7 +32,7 @@ class TextRun extends Text $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - $this->writeOpeningWP(); + $this->startElementP(); $containerWriter = new Container($xmlWriter, $element); $containerWriter->write(); diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 507c0c02..6926081f 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -134,6 +134,7 @@ class Frame extends AbstractStyle /** * Get style values in associative array * + * @param \PhpOffice\PhpWord\Style\Frame $style * @param array $properties * @param string $suffix * @return array From 3d2cd163d385be827b61daabf1c85f8e23af5ad3 Mon Sep 17 00:00:00 2001 From: Andrew Collins Date: Thu, 5 Jun 2014 13:45:18 -0400 Subject: [PATCH 245/326] Ensure temp file in pclzipAddFile() removed Make pclzipAddFile() similar to pclzipAddFromString() in removing temporary files. --- src/PhpWord/Shared/ZipArchive.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index cbfcb071..8bbfd4c3 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -224,7 +224,9 @@ class ZipArchive // To Rename the file while adding it to the zip we // need to create a temp file with the correct name + $temp_file = false; if ($filenameParts['basename'] != $localnameParts['basename']) { + $temp_file = true; // temp file created $temppath = $this->tempDir . '/' . $localnameParts['basename']; copy($filename, $temppath); $filename = $temppath; @@ -236,6 +238,11 @@ class ZipArchive $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); + if($temp_file) { + // Remove temp file, if created + @unlink($this->tempDir . '/' . $localnameParts["basename"]); + } + return ($res == 0) ? false : true; } From 49f4e6ba64601a80dcdd3af5e2a451a98ef79033 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 6 Jun 2014 12:53:01 +0700 Subject: [PATCH 246/326] RTF Writer: Support for sections, margins, and borders #249 --- CHANGELOG.md | 1 + .../Writer/HTML/Style/AbstractStyle.php | 27 ++++ src/PhpWord/Writer/RTF/Part/Document.php | 13 +- src/PhpWord/Writer/RTF/Part/Header.php | 36 ++++- src/PhpWord/Writer/RTF/Style/Border.php | 124 ++++++++++++++++++ src/PhpWord/Writer/RTF/Style/Section.php | 69 ++++++++++ tests/PhpWord/Tests/Writer/RTF/StyleTest.php | 2 +- 7 files changed, 263 insertions(+), 9 deletions(-) create mode 100644 src/PhpWord/Writer/RTF/Style/Border.php create mode 100644 src/PhpWord/Writer/RTF/Style/Section.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d22c8f..f176fa44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin GH-123 - Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin - Paragraph: Added shading to the paragraph style for full width shading - @lrobert GH-264 +- RTF Writer: Support for sections, margins, and borders - @ivanlanin GH-249 ### Bugfixes diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index cd37174a..c729ec55 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -26,6 +26,13 @@ use PhpOffice\PhpWord\Style\AbstractStyle as Style; */ abstract class AbstractStyle { + /** + * Parent writer + * + * @var \PhpOffice\PhpWord\Writer\AbstractWriter + */ + private $parentWriter; + /** * Style * @@ -48,6 +55,26 @@ abstract class AbstractStyle $this->style = $style; } + /** + * Set parent writer + * + * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + */ + public function setParentWriter($writer) + { + $this->parentWriter = $writer; + } + + /** + * Get parent writer + * + * @return \PhpOffice\PhpWord\Writer\AbstractWriter + */ + public function getParentWriter() + { + return $this->parentWriter; + } + /** * Get style * diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 71565044..2f5c2f8e 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -19,11 +19,13 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\RTF\Element\Container; +use PhpOffice\PhpWord\Writer\RTF\Style\Section as SectionStyleWriter; /** * RTF document part writer * * @since 0.11.0 + * @link http://www.biblioscape.com/rtf15_spec.htm#Heading24 */ class Document extends AbstractPart { @@ -103,12 +105,19 @@ class Document extends AbstractPart */ private function writeSections() { + $content = ''; $sections = $this->getParentWriter()->getPhpWord()->getSections(); foreach ($sections as $section) { - $writer = new Container($this->getParentWriter(), $section); - $content .= $writer->write(); + $styleWriter = new SectionStyleWriter($section->getSettings()); + $styleWriter->setParentWriter($this->getParentWriter()); + $content .= $styleWriter->write(); + + $elementWriter = new Container($this->getParentWriter(), $section); + $content .= $elementWriter->write(); + + $content .= '\sect' . PHP_EOL; } return $content; diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 15a0c303..32debb06 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -25,7 +25,15 @@ use PhpOffice\PhpWord\Style\Font; /** * RTF header part writer * + * - Character set + * - Font table + * - File table (not supported yet) + * - Color table + * - Style sheet (not supported yet) + * - List table (not supported yet) + * * @since 0.11.0 + * @link http://www.biblioscape.com/rtf15_spec.htm#Heading6 */ class Header extends AbstractPart { @@ -141,10 +149,10 @@ class Header extends AbstractPart $content = ''; $content .= '{'; - $content .= '\colortbl'; + $content .= '\colortbl;'; foreach ($this->colorTable as $color) { list($red, $green, $blue) = Drawing::htmlToRGB($color); - $content .= ";\\red{$red}\\green{$green}\\blue{$blue}"; + $content .= "\\red{$red}\\green{$green}\\blue{$blue};"; } $content .= '}'; $content .= PHP_EOL; @@ -185,6 +193,7 @@ class Header extends AbstractPart $sections = $phpWord->getSections(); foreach ($sections as $section) { $elements = $section->getElements(); + $this->registerBorderColor($section->getSettings()); foreach ($elements as $element) { if (method_exists($element, 'getFontStyle')) { $style = $element->getFontStyle(); @@ -194,6 +203,21 @@ class Header extends AbstractPart } } + /** + * Register border colors + * + * @param \PhpOffice\PhpWord\Style\Border $style + */ + private function registerBorderColor($style) + { + $colors = $style->getBorderColor(); + foreach ($colors as $color) { + if ($color !== null) { + $this->registerTableItem($this->colorTable, $color); + } + } + } + /** * Register fonts and colors * @@ -205,9 +229,9 @@ class Header extends AbstractPart $defaultColor = Settings::DEFAULT_FONT_COLOR; if ($style instanceof Font) { - $this->registerFontItem($this->fontTable, $style->getName(), $defaultFont); - $this->registerFontItem($this->colorTable, $style->getColor(), $defaultColor); - $this->registerFontItem($this->colorTable, $style->getFgColor(), $defaultColor); + $this->registerTableItem($this->fontTable, $style->getName(), $defaultFont); + $this->registerTableItem($this->colorTable, $style->getColor(), $defaultColor); + $this->registerTableItem($this->colorTable, $style->getFgColor(), $defaultColor); } } @@ -218,7 +242,7 @@ class Header extends AbstractPart * @param string $value * @param string $default */ - private function registerFontItem(&$table, $value, $default) + private function registerTableItem(&$table, $value, $default = null) { if (in_array($value, $table) === false && $value !== null && $value != $default) { $table[] = $value; diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php new file mode 100644 index 00000000..8df6d165 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -0,0 +1,124 @@ +sizes) - 1; + + // Page border measure + // 8 = from text, infront off; 32 = from edge, infront on; 40 = from edge, infront off + $content .= '\pgbrdropt32'; + + for ($i = 0; $i < $sizeCount; $i++) { + if ($this->sizes[$i] !== null) { + $color = null; + if (isset($this->colors[$i])) { + $color = $this->colors[$i]; + } + $content .= $this->writeSide($sides[$i], $this->sizes[$i], $color); + } + } + + return $content; + } + + /** + * Write side + * + * @param string $side + * @param int $width + * @param string $color + * @return string + */ + private function writeSide($side, $width, $color = '') + { + /** @var \PhpOffice\PhpWord\Writer\RTF $rtfWriter */ + $rtfWriter = $this->getParentWriter(); + $colorIndex = 0; + if ($rtfWriter !== null) { + $colorTable = $rtfWriter->getColorTable(); + $index = array_search($color, $colorTable); + if ($index !== false && $colorIndex !== null) { + $colorIndex = $index + 1; + } + } + + $content = ''; + + $content .= '\pgbrdr' . substr($side, 0, 1); + $content .= '\brdrs'; // Single-thickness border; @todo Get other type of border + $content .= '\brdrw' . $width; // Width + $content .= '\brdrcf' . $colorIndex; // Color + $content .= '\brsp480'; // Space in twips between borders and the paragraph (24pt, following OOXML) + $content .= ' '; + + return $content; + } + + /** + * Set sizes + * + * @param integer[] $value + */ + public function setSizes($value) + { + $this->sizes = $value; + } + + /** + * Set colors + * + * @param string[] $value + */ + public function setColors($value) + { + $this->colors = $value; + } +} diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php new file mode 100644 index 00000000..b556e299 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -0,0 +1,69 @@ +getStyle(); + if (!$style instanceof SectionStyle) { + return ''; + } + + $content = ''; + + $content .= '\sectd '; + + // Size & margin + $content .= $this->getValueIf($style->getPageSizeW(), '\pgwsxn' . $style->getPageSizeW()); + $content .= $this->getValueIf($style->getPageSizeH(), '\pghsxn' . $style->getPageSizeH()); + $content .= ' '; + $content .= $this->getValueIf($style->getMarginTop(), '\margtsxn' . $style->getMarginTop()); + $content .= $this->getValueIf($style->getMarginRight(), '\margrsxn' . $style->getMarginRight()); + $content .= $this->getValueIf($style->getMarginBottom(), '\margbsxn' . $style->getMarginBottom()); + $content .= $this->getValueIf($style->getMarginLeft(), '\marglsxn' . $style->getMarginLeft()); + $content .= $this->getValueIf($style->getHeaderHeight(), '\headery' . $style->getHeaderHeight()); + $content .= $this->getValueIf($style->getFooterHeight(), '\footery' . $style->getFooterHeight()); + $content .= $this->getValueIf($style->getGutter(), '\guttersxn' . $style->getGutter()); + $content .= ' '; + + // Borders + if ($style->hasBorder()) { + $styleWriter = new Border($style); + $styleWriter->setParentWriter($this->getParentWriter()); + $styleWriter->setSizes($style->getBorderSize()); + $styleWriter->setColors($style->getBorderColor()); + $content .= $styleWriter->write(); + } + + return $content . PHP_EOL; + } +} diff --git a/tests/PhpWord/Tests/Writer/RTF/StyleTest.php b/tests/PhpWord/Tests/Writer/RTF/StyleTest.php index 8b4a4441..542e34fe 100644 --- a/tests/PhpWord/Tests/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/RTF/StyleTest.php @@ -28,7 +28,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase */ public function testEmptyStyles() { - $styles = array('Font', 'Paragraph'); + $styles = array('Font', 'Paragraph', 'Section'); foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Style\\' . $style; $object = new $objectClass(); From a2ec62a79fb2e9ef51aa021ac84c174231d65e5a Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 6 Jun 2014 15:23:19 +0700 Subject: [PATCH 247/326] Section: Ability to set paper size, e.g. A4, A3, and Legal --- CHANGELOG.md | 1 + composer.lock | 219 +++++++++------------- samples/Sample_03_Sections.php | 4 +- src/PhpWord/Style/Paper.php | 188 +++++++++++++++++++ src/PhpWord/Style/Section.php | 47 ++++- src/PhpWord/Writer/RTF/Style/Border.php | 2 - tests/PhpWord/Tests/Style/SectionTest.php | 16 +- 7 files changed, 328 insertions(+), 149 deletions(-) create mode 100644 src/PhpWord/Style/Paper.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f176fa44..eb0a6c20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin - Paragraph: Added shading to the paragraph style for full width shading - @lrobert GH-264 - RTF Writer: Support for sections, margins, and borders - @ivanlanin GH-249 +- Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin GH-249 ### Bugfixes diff --git a/composer.lock b/composer.lock index 172e564e..11a38043 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "91993ff980d11a416fcf3a7309a4044f", + "hash": "7d0a883164ca8e64ca34f4910aa64b96", "packages": [ ], @@ -553,16 +553,16 @@ }, { "name": "monolog/monolog", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "65026b610f8c19e61d7242f600530677b0466aac" + "reference": "25b16e801979098cb2f120e697bfce454b18bf23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/65026b610f8c19e61d7242f600530677b0466aac", - "reference": "65026b610f8c19e61d7242f600530677b0466aac", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/25b16e801979098cb2f120e697bfce454b18bf23", + "reference": "25b16e801979098cb2f120e697bfce454b18bf23", "shasum": "" }, "require": { @@ -590,7 +590,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { @@ -617,7 +617,7 @@ "logging", "psr-3" ], - "time": "2014-04-24 13:29:03" + "time": "2014-06-04 16:30:04" }, { "name": "mpdf/mpdf", @@ -1984,17 +1984,17 @@ }, { "name": "symfony/config", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Config", "source": { "type": "git", "url": "https://github.com/symfony/Config.git", - "reference": "2effc67af6f21a0d267210b72d0b0b691d113528" + "reference": "9c8caadb38ecc69ac35ab31af4d1996944b5a09f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/2effc67af6f21a0d267210b72d0b0b691d113528", - "reference": "2effc67af6f21a0d267210b72d0b0b691d113528", + "url": "https://api.github.com/repos/symfony/Config/zipball/9c8caadb38ecc69ac35ab31af4d1996944b5a09f", + "reference": "9c8caadb38ecc69ac35ab31af4d1996944b5a09f", "shasum": "" }, "require": { @@ -2004,7 +2004,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2030,36 +2030,38 @@ ], "description": "Symfony Config Component", "homepage": "http://symfony.com", - "time": "2014-04-22 08:11:06" + "time": "2014-04-22 08:11:23" }, { "name": "symfony/console", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "2e452005b1e1d003d23702d227e23614679eb5ca" + "reference": "ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/2e452005b1e1d003d23702d227e23614679eb5ca", - "reference": "2e452005b1e1d003d23702d227e23614679eb5ca", + "url": "https://api.github.com/repos/symfony/Console/zipball/ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c", + "reference": "ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { + "psr/log": "~1.0", "symfony/event-dispatcher": "~2.1" }, "suggest": { + "psr/log": "For using the console logger", "symfony/event-dispatcher": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2085,28 +2087,31 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2014-04-27 13:34:57" + "time": "2014-05-22 08:54:24" }, { "name": "symfony/event-dispatcher", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "e539602e5455aa086c0e81e604745af7789e4d8a" + "reference": "cb62ec8dd05893fc8e4f0e6e21e326e1fc731fe8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/e539602e5455aa086c0e81e604745af7789e4d8a", - "reference": "e539602e5455aa086c0e81e604745af7789e4d8a", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/cb62ec8dd05893fc8e4f0e6e21e326e1fc731fe8", + "reference": "cb62ec8dd05893fc8e4f0e6e21e326e1fc731fe8", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "symfony/dependency-injection": "~2.0" + "psr/log": "~1.0", + "symfony/config": "~2.0", + "symfony/dependency-injection": "~2.0", + "symfony/stopwatch": "~2.2" }, "suggest": { "symfony/dependency-injection": "", @@ -2115,7 +2120,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2141,21 +2146,21 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "http://symfony.com", - "time": "2014-04-16 10:34:31" + "time": "2014-04-29 10:13:57" }, { "name": "symfony/filesystem", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Filesystem", "source": { "type": "git", "url": "https://github.com/symfony/Filesystem.git", - "reference": "a3af8294bcce4a7c1b2892363b0c9d8109affad4" + "reference": "98e831eac836a0a5911626ce82684155f21d0e4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/a3af8294bcce4a7c1b2892363b0c9d8109affad4", - "reference": "a3af8294bcce4a7c1b2892363b0c9d8109affad4", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/98e831eac836a0a5911626ce82684155f21d0e4d", + "reference": "98e831eac836a0a5911626ce82684155f21d0e4d", "shasum": "" }, "require": { @@ -2164,7 +2169,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2190,21 +2195,21 @@ ], "description": "Symfony Filesystem Component", "homepage": "http://symfony.com", - "time": "2014-04-16 10:34:31" + "time": "2014-04-16 10:36:21" }, { "name": "symfony/finder", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "25e1e7d5e7376f8a92ae3b1d714d956edf33a730" + "reference": "307aad2c541bbdf43183043645e186ef2cd6b973" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/25e1e7d5e7376f8a92ae3b1d714d956edf33a730", - "reference": "25e1e7d5e7376f8a92ae3b1d714d956edf33a730", + "url": "https://api.github.com/repos/symfony/Finder/zipball/307aad2c541bbdf43183043645e186ef2cd6b973", + "reference": "307aad2c541bbdf43183043645e186ef2cd6b973", "shasum": "" }, "require": { @@ -2213,7 +2218,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2239,21 +2244,21 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2014-04-27 13:34:57" + "time": "2014-05-22 13:47:45" }, { "name": "symfony/process", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Process", "source": { "type": "git", "url": "https://github.com/symfony/Process.git", - "reference": "8721f1476d5d38a43c7d6ccb6435b351cf8f3bb7" + "reference": "5d7d78e23894544740219e006320678cfa4cd45b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/8721f1476d5d38a43c7d6ccb6435b351cf8f3bb7", - "reference": "8721f1476d5d38a43c7d6ccb6435b351cf8f3bb7", + "url": "https://api.github.com/repos/symfony/Process/zipball/5d7d78e23894544740219e006320678cfa4cd45b", + "reference": "5d7d78e23894544740219e006320678cfa4cd45b", "shasum": "" }, "require": { @@ -2262,7 +2267,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2288,81 +2293,21 @@ ], "description": "Symfony Process Component", "homepage": "http://symfony.com", - "time": "2014-04-27 13:34:57" - }, - { - "name": "symfony/property-access", - "version": "v2.4.4", - "target-dir": "Symfony/Component/PropertyAccess", - "source": { - "type": "git", - "url": "https://github.com/symfony/PropertyAccess.git", - "reference": "0456222bc00c40c1365065b603f7c397fb9a7134" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/0456222bc00c40c1365065b603f7c397fb9a7134", - "reference": "0456222bc00c40c1365065b603f7c397fb9a7134", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\PropertyAccess\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony PropertyAccess Component", - "homepage": "http://symfony.com", - "keywords": [ - "access", - "array", - "extraction", - "index", - "injection", - "object", - "property", - "property path", - "reflection" - ], - "time": "2014-04-18 20:37:09" + "time": "2014-05-23 09:02:52" }, { "name": "symfony/stopwatch", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Stopwatch", "source": { "type": "git", "url": "https://github.com/symfony/Stopwatch.git", - "reference": "343bcc0360f2c22f371884b8f6a9fee8d1aa431a" + "reference": "724d73604ebe6c1c9bdf36533b556123bd9075a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/343bcc0360f2c22f371884b8f6a9fee8d1aa431a", - "reference": "343bcc0360f2c22f371884b8f6a9fee8d1aa431a", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/724d73604ebe6c1c9bdf36533b556123bd9075a1", + "reference": "724d73604ebe6c1c9bdf36533b556123bd9075a1", "shasum": "" }, "require": { @@ -2371,7 +2316,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2397,21 +2342,21 @@ ], "description": "Symfony Stopwatch Component", "homepage": "http://symfony.com", - "time": "2014-04-18 20:37:09" + "time": "2014-04-18 20:40:13" }, { "name": "symfony/translation", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "d2c73ffa4a5ba1fa0c5d93f43b68331dffe898c5" + "reference": "5f23265dcf8927a84be832608069c9edca3cf5f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/d2c73ffa4a5ba1fa0c5d93f43b68331dffe898c5", - "reference": "d2c73ffa4a5ba1fa0c5d93f43b68331dffe898c5", + "url": "https://api.github.com/repos/symfony/Translation/zipball/5f23265dcf8927a84be832608069c9edca3cf5f4", + "reference": "5f23265dcf8927a84be832608069c9edca3cf5f4", "shasum": "" }, "require": { @@ -2428,7 +2373,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2454,48 +2399,53 @@ ], "description": "Symfony Translation Component", "homepage": "http://symfony.com", - "time": "2014-04-18 21:02:05" + "time": "2014-05-22 13:47:45" }, { "name": "symfony/validator", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Validator", "source": { "type": "git", "url": "https://github.com/symfony/Validator.git", - "reference": "5bbcdcc520bc7fb3826abb44020880f14c9c03a7" + "reference": "62f6f7735fbd3897b9347ae60fda4a40d0122640" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Validator/zipball/5bbcdcc520bc7fb3826abb44020880f14c9c03a7", - "reference": "5bbcdcc520bc7fb3826abb44020880f14c9c03a7", + "url": "https://api.github.com/repos/symfony/Validator/zipball/62f6f7735fbd3897b9347ae60fda4a40d0122640", + "reference": "62f6f7735fbd3897b9347ae60fda4a40d0122640", "shasum": "" }, "require": { "php": ">=5.3.3", - "symfony/property-access": "~2.2", "symfony/translation": "~2.0" }, "require-dev": { "doctrine/annotations": "~1.0", "doctrine/cache": "~1.0", + "egulias/email-validator": "~1.0", "symfony/config": "~2.2", + "symfony/expression-language": "~2.4", "symfony/http-foundation": "~2.1", "symfony/intl": "~2.3", + "symfony/property-access": "~2.2", "symfony/yaml": "~2.0" }, "suggest": { "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", - "doctrine/cache": "For using the default cached annotation reader", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "egulias/email-validator": "Strict (RFC compliant) email validation", "symfony/config": "", + "symfony/expression-language": "For using the 2.4 Expression validator", "symfony/http-foundation": "", "symfony/intl": "", + "symfony/property-access": "For using the 2.4 Validator API", "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2521,21 +2471,21 @@ ], "description": "Symfony Validator Component", "homepage": "http://symfony.com", - "time": "2014-04-27 13:34:57" + "time": "2014-05-31 02:02:56" }, { "name": "symfony/yaml", - "version": "v2.4.4", + "version": "v2.5.0", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "65539ecde838f9c0d18b006b2101e3deb4b5c9ff" + "reference": "b4b09c68ec2f2727574544ef0173684281a5033c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/65539ecde838f9c0d18b006b2101e3deb4b5c9ff", - "reference": "65539ecde838f9c0d18b006b2101e3deb4b5c9ff", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/b4b09c68ec2f2727574544ef0173684281a5033c", + "reference": "b4b09c68ec2f2727574544ef0173684281a5033c", "shasum": "" }, "require": { @@ -2544,7 +2494,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2570,15 +2520,15 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2014-04-18 20:37:09" + "time": "2014-05-16 14:25:18" }, { "name": "tecnick.com/tcpdf", - "version": "6.0.078", + "version": "6.0.083", "source": { "type": "git", "url": "git://git.code.sf.net/p/tcpdf/code", - "reference": "e1cbda79b99f3cdc8fdf26b39eb4870d2cd9fbac" + "reference": "d6a2206ab366f493680a22151429f17fd045fe04" }, "require": { "php": ">=5.3.0" @@ -2627,7 +2577,7 @@ "pdf417", "qrcode" ], - "time": "2014-05-12 19:50:13" + "time": "2014-05-29 18:28:56" }, { "name": "twig/twig", @@ -3274,8 +3224,7 @@ ], "platform": { "php": ">=5.3.3", - "ext-xml": "*", - "ext-zip": "*" + "ext-xml": "*" }, "platform-dev": [ diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index bfbc84af..9ed75c73 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -16,8 +16,8 @@ $section->addPageBreak(); $section->addPageBreak(); // New portrait section -$section = $phpWord->addSection(array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); -$section->addText('This section uses other margins.'); +$section = $phpWord->addSection(array('paperSize' => 'Folio', 'marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); +$section->addText('This section uses other margins with folio papersize.'); // New portrait section with Header & Footer $section = $phpWord->addSection(array('marginLeft' => 200, 'marginRight' => 200, 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50,)); diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php new file mode 100644 index 00000000..642666b5 --- /dev/null +++ b/src/PhpWord/Style/Paper.php @@ -0,0 +1,188 @@ + array(297, 420, 'mm'), + 'A4' => array(210, 297, 'mm'), + 'A5' => array(148, 210, 'mm'), + 'Folio' => array(8.5, 13, 'in'), + 'Legal' => array(8.5, 14, 'in'), + 'Letter' => array(8.5, 11, 'in'), + ); + + /** + * Paper size + * + * @var string + */ + private $size = 'A4'; + + /** + * Width + * + * @var int (twip) + */ + private $width; + + /** + * Height + * + * @var int (twip) + */ + private $height; + + /** + * Create a new instance + * + * @param string $size + */ + public function __construct($size = 'A4') + { + $this->setSize($size); + } + + /** + * Get size + * + * @return string + */ + public function getSize() + { + return $this->size; + } + + /** + * Set size + * + * @param string $size + * @return self + */ + public function setSize($size) + { + $this->size = $this->setEnumVal($size, array_keys($this->sizes), $this->size); + + list($width, $height, $unit) = $this->sizes[$this->size]; + $multipliers = array('mm' => 56.5217, 'in' => 1440); + $multiplier = $multipliers[$unit]; + + $this->width = (int)round($width * $multiplier); + $this->height = (int)round($height * $multiplier); + + return $this; + } + + /** + * Get width + * + * @return int + */ + public function getWidth() + { + return $this->width; + } + + /** + * Get height + * + * @return int + */ + public function getHeight() + { + return $this->height; + } +} diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index fd59f1b4..c56b0a19 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -35,8 +35,8 @@ class Section extends Border * * @const int|float */ - const DEFAULT_WIDTH = 11906; // In twip - const DEFAULT_HEIGHT = 16838; // In twip + const DEFAULT_WIDTH = 11870; // In twip + const DEFAULT_HEIGHT = 16787; // In twip const DEFAULT_MARGIN = 1440; // In twip const DEFAULT_GUTTER = 0; // In twip const DEFAULT_HEADER_HEIGHT = 720; // In twip @@ -52,6 +52,13 @@ class Section extends Border */ private $orientation = self::ORIENTATION_PORTRAIT; + /** + * Paper size + * + * @var \PhpOffice\PhpWord\Style\Paper + */ + private $paper; + /** * Page Size Width * @@ -159,6 +166,42 @@ class Section extends Border */ private $lineNumbering; + /** + * Create new instance + */ + public function __construct() + { + $this->setPaperSize(); + } + + /** + * Get paper size + * + * @return string + */ + public function getPaperSize() + { + return $this->paper->getSize(); + } + + /** + * Set paper size + * + * @param string $value + * @return self + */ + public function setPaperSize($value = 'A4') + { + if ($this->paper === null) { + $this->paper = new Paper(); + } + $this->paper->setSize($value); + $this->pageSizeW = $this->paper->getWidth(); + $this->pageSizeH = $this->paper->getHeight(); + + return $this; + } + /** * Set Setting Value * diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 8df6d165..8bb9703f 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; - /** * Border style writer * diff --git a/tests/PhpWord/Tests/Style/SectionTest.php b/tests/PhpWord/Tests/Style/SectionTest.php index dd7273cb..de582948 100644 --- a/tests/PhpWord/Tests/Style/SectionTest.php +++ b/tests/PhpWord/Tests/Style/SectionTest.php @@ -35,13 +35,13 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $oSettings = new Section(); $this->assertEquals('portrait', $oSettings->getOrientation()); - $this->assertEquals(11906, $oSettings->getPageSizeW()); - $this->assertEquals(16838, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH()); $oSettings->setSettingValue('orientation', 'landscape'); $this->assertEquals('landscape', $oSettings->getOrientation()); - $this->assertEquals(16838, $oSettings->getPageSizeW()); - $this->assertEquals(11906, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH()); $iVal = rand(1, 1000); $oSettings->setSettingValue('borderSize', $iVal); @@ -106,8 +106,8 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $oSettings->setLandscape(); $this->assertEquals('landscape', $oSettings->getOrientation()); - $this->assertEquals(16838, $oSettings->getPageSizeW()); - $this->assertEquals(11906, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH()); } /** @@ -120,8 +120,8 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $oSettings->setPortrait(); $this->assertEquals('portrait', $oSettings->getOrientation()); - $this->assertEquals(11906, $oSettings->getPageSizeW()); - $this->assertEquals(16838, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH()); } /** From 09a143fe71334bb599db1833b929b87972bf227d Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 6 Jun 2014 18:56:09 +0700 Subject: [PATCH 248/326] QA: Type check fix for RTF section style and docblock comment fix for AbstractContainer --- src/PhpWord/Element/AbstractContainer.php | 34 +++++++++++------------ src/PhpWord/Writer/RTF/Style/Section.php | 18 ++++++------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 7afdbb47..701b888c 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -23,23 +23,23 @@ use PhpOffice\PhpWord\PhpWord; /** * Container abstract class * - * @method Text addText($text, $fStyle = null, $pStyle = null) - * @method TextRun addTextRun($pStyle = null) - * @method Link addLink($target, $text = null, $fStyle = null, $pStyle = null) - * @method PreserveText addPreserveText($text, $fStyle = null, $pStyle = null) - * @method void addTextBreak($count = 1, $fStyle = null, $pStyle = null) - * @method ListItem addListItem($text, $depth = 0, $fStyle = null, $listStyle = null, $pStyle = null) - * @method ListItemRun addListItemRun($depth = 0, $listStyle = null, $pStyle = null) - * @method Table addTable($style = null) - * @method Image addImage($source, $style = null, $isWatermark = false) - * @method Object addObject($source, $style = null) - * @method Footnote addFootnote($pStyle = null) - * @method Endnote addEndnote($pStyle = null) - * @method CheckBox addCheckBox($name, $text, $fStyle = null, $pStyle = null) - * @method TextBox addTextBox($style = null) - * @method Field addField($type = null, $properties = array(), $options = array()) - * @method Line addLine($lineStyle = null) - * @method Shape addObject($type, $style = null) + * @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null) + * @method TextRun addTextRun(mixed $pStyle = null) + * @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null) + * @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null) + * @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null) + * @method ListItem addListItem(string $text, int $depth = 0, mixed $fStyle = null, mixed $listStyle = null, mixed $pStyle = null) + * @method ListItemRun addListItemRun(int $depth = 0, mixed $listStyle = null, mixed $pStyle = null) + * @method Footnote addFootnote(mixed $pStyle = null) + * @method Endnote addEndnote(mixed $pStyle = null) + * @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null) + * @method Table addTable(mixed $style = null) + * @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false) + * @method Object addObject(string $source, mixed $style = null) + * @method TextBox addTextBox(mixed $style = null) + * @method Field addField(string $type = null, array $properties = array(), array $options = array()) + * @method Line addLine(mixed $lineStyle = null) + * @method Shape addObject(string $type, mixed $style = null) * * @since 0.10.0 */ diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index b556e299..4169b630 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -43,16 +43,16 @@ class Section extends AbstractStyle $content .= '\sectd '; // Size & margin - $content .= $this->getValueIf($style->getPageSizeW(), '\pgwsxn' . $style->getPageSizeW()); - $content .= $this->getValueIf($style->getPageSizeH(), '\pghsxn' . $style->getPageSizeH()); + $content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . $style->getPageSizeW()); + $content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . $style->getPageSizeH()); $content .= ' '; - $content .= $this->getValueIf($style->getMarginTop(), '\margtsxn' . $style->getMarginTop()); - $content .= $this->getValueIf($style->getMarginRight(), '\margrsxn' . $style->getMarginRight()); - $content .= $this->getValueIf($style->getMarginBottom(), '\margbsxn' . $style->getMarginBottom()); - $content .= $this->getValueIf($style->getMarginLeft(), '\marglsxn' . $style->getMarginLeft()); - $content .= $this->getValueIf($style->getHeaderHeight(), '\headery' . $style->getHeaderHeight()); - $content .= $this->getValueIf($style->getFooterHeight(), '\footery' . $style->getFooterHeight()); - $content .= $this->getValueIf($style->getGutter(), '\guttersxn' . $style->getGutter()); + $content .= $this->getValueIf($style->getMarginTop() !== null, '\margtsxn' . $style->getMarginTop()); + $content .= $this->getValueIf($style->getMarginRight() !== null, '\margrsxn' . $style->getMarginRight()); + $content .= $this->getValueIf($style->getMarginBottom() !== null, '\margbsxn' . $style->getMarginBottom()); + $content .= $this->getValueIf($style->getMarginLeft() !== null, '\marglsxn' . $style->getMarginLeft()); + $content .= $this->getValueIf($style->getHeaderHeight() !== null, '\headery' . $style->getHeaderHeight()); + $content .= $this->getValueIf($style->getFooterHeight() !== null, '\footery' . $style->getFooterHeight()); + $content .= $this->getValueIf($style->getGutter() !== null, '\guttersxn' . $style->getGutter()); $content .= ' '; // Borders From 8b0472dd528f5ab236a5a5b1b3e0cab55920cdec Mon Sep 17 00:00:00 2001 From: Brandon Skrtich Date: Fri, 6 Jun 2014 13:34:01 -0600 Subject: [PATCH 249/326] Autoloader Options Add the ability to set the autoloader options. --- src/PhpWord/Autoloader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index c467f836..d7e154bb 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -30,9 +30,9 @@ class Autoloader * * @return void */ - public static function register() + public static function register($throw = true, $prepend = false) { - spl_autoload_register(array(new self, 'autoload')); + spl_autoload_register(array(new self, 'autoload'), $throw, $prepend); } /** From 01853f7aacde43a071be45d8410b1667905bc878 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 7 Jun 2014 17:48:45 +0700 Subject: [PATCH 250/326] Update change log and adjust some coding standards for #261, #265, and #267 --- CHANGELOG.md | 4 +++- src/PhpWord/Autoloader.php | 2 ++ src/PhpWord/Shared/ZipArchive.php | 15 +++++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb0a6c20..a2f52bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Bugfixes -None yet. +- Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo GH-261 ### Deprecated @@ -23,6 +23,8 @@ None yet. ### Miscellaneous - Docs: Add known issue on `README` about requirement for temporary folder to be writable and update `samples/index.php` for this requirement check - @ivanlanin GH-238 +- PclZip: Remove temporary file after used - @andrew-kzoo GH-265 +- Autoloader: Add the ability to set the autoloader options - @bskrtich GH-267 ## 0.11.1 - 2 June 2014 diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index d7e154bb..dbc42187 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -28,6 +28,8 @@ class Autoloader /** * Register * + * @param bool $throw + * @param bool $prepend * @return void */ public static function register($throw = true, $prepend = false) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 2e6daa13..7515c5b5 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -218,18 +218,21 @@ class ZipArchive { /** @var \PclZip $zip Type hint */ $zip = $this->zip; - $test_filename = realpath($filename); - if($test_filename !== false) { - $filename = $test_filename; + + // Bugfix GH-261 https://github.com/PHPOffice/PHPWord/pull/261 + $realpathFilename = realpath($filename); + if ($realpathFilename !== false) { + $filename = $realpathFilename; } + $filenameParts = pathinfo($filename); $localnameParts = pathinfo($localname); // To Rename the file while adding it to the zip we // need to create a temp file with the correct name - $temp_file = false; + $tempFile = false; if ($filenameParts['basename'] != $localnameParts['basename']) { - $temp_file = true; // temp file created + $tempFile = true; // temp file created $temppath = $this->tempDir . '/' . $localnameParts['basename']; copy($filename, $temppath); $filename = $temppath; @@ -241,7 +244,7 @@ class ZipArchive $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); - if($temp_file) { + if ($tempFile) { // Remove temp file, if created @unlink($this->tempDir . '/' . $localnameParts["basename"]); } From 893843969f3906824484a75ee98885d3c1c77e5a Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 02:31:44 +0700 Subject: [PATCH 251/326] Refactor elements to move set relation Id from container to element --- CHANGELOG.md | 5 +- src/PhpWord/Element/AbstractContainer.php | 90 ++------------- src/PhpWord/Element/AbstractElement.php | 108 +++++++++++++++++- src/PhpWord/Element/Footnote.php | 8 ++ src/PhpWord/Element/Image.php | 7 ++ src/PhpWord/Element/Link.php | 38 ++++-- src/PhpWord/Element/Object.php | 7 ++ src/PhpWord/Element/Row.php | 4 +- src/PhpWord/Element/Section.php | 34 ------ src/PhpWord/Element/Table.php | 4 +- src/PhpWord/Element/Title.php | 7 ++ src/PhpWord/Reader/Word2007/AbstractPart.php | 4 +- src/PhpWord/Writer/HTML/Element/Link.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- src/PhpWord/Writer/RTF/Element/Link.php | 2 +- src/PhpWord/Writer/Word2007/Style/Font.php | 6 +- .../Writer/Word2007/Style/Paragraph.php | 4 +- tests/PhpWord/Tests/Element/LinkTest.php | 6 +- .../PhpWord/Tests/Element/ListItemRunTest.php | 4 +- tests/PhpWord/Tests/Element/TextRunTest.php | 4 +- tests/PhpWord/Tests/Style/SectionTest.php | 1 + 21 files changed, 195 insertions(+), 152 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2f52bde..7acfecee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.12.0 - Not yet released +This release added drawing shapes (arc, curve, line, polyline, rect, oval) element and some new styles. + ### Features - Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin GH-123 @@ -18,13 +20,14 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Deprecated -None yet. +- `Element\Link::getTarget()` replaced by `Element\Link::getSource()` ### Miscellaneous - Docs: Add known issue on `README` about requirement for temporary folder to be writable and update `samples/index.php` for this requirement check - @ivanlanin GH-238 - PclZip: Remove temporary file after used - @andrew-kzoo GH-265 - Autoloader: Add the ability to set the autoloader options - @bskrtich GH-267 +- Element: Refactor elements to move set relation Id from container to element - @ivanlanin ## 0.11.1 - 2 June 2014 diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 701b888c..64c4b768 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -17,9 +17,6 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\PhpWord; - /** * Container abstract class * @@ -33,6 +30,10 @@ use PhpOffice\PhpWord\PhpWord; * @method Footnote addFootnote(mixed $pStyle = null) * @method Endnote addEndnote(mixed $pStyle = null) * @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null) + * @method Title addTitle(string $text, int $depth = 1) + * @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9) + * + * @method PageBreak addPageBreak() * @method Table addTable(mixed $style = null) * @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false) * @method Object addObject(string $source, mixed $style = null) @@ -125,10 +126,6 @@ abstract class AbstractContainer extends AbstractElement if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { $args[3] = null; // Remove paragraph style for texts in textrun } - $source = ''; - if (count($args) > 1) { - $source = $args[1]; - } // Create element using reflection $reflection = new \ReflectionClass($elementClass); @@ -138,15 +135,10 @@ abstract class AbstractContainer extends AbstractElement /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ $element = $reflection->newInstanceArgs($elementArgs); - // Set nested level and relation Id - $this->setElementNestedLevel($element); - $this->setElementRelationId($element, $elementName, $source); - - // Set other properties and add element into collection - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); + // Set parent container + $element->setParentContainer($this); $element->setElementIndex($this->countElements() + 1); $element->setElementId(); - $element->setPhpWord($this->phpWord); $this->elements[] = $element; @@ -173,55 +165,6 @@ abstract class AbstractContainer extends AbstractElement return count($this->elements); } - /** - * Set element nested level based on container; add one when it's inside a cell - */ - private function setElementNestedLevel(AbstractElement $element) - { - if ($this->container == 'Cell') { - $element->setNestedLevel($this->getNestedLevel() + 1); - } else { - $element->setNestedLevel($this->getNestedLevel()); - } - } - - /** - * Set relation Id - * - * @param \PhpOffice\PhpWord\Element\AbstractElement $element - * @param string $elementName - * @param string $source - */ - private function setElementRelationId(AbstractElement $element, $elementName, $source) - { - $mediaContainer = $this->getMediaContainer(); - $hasMediaRelation = in_array($elementName, array('Link', 'Image', 'Object')); - $hasOtherRelation = in_array($elementName, array('Footnote', 'Endnote', 'Title')); - - // Set relation Id for media elements (link, image, object; legacy of OOXML) - // Only Image that needs to be passed to Media class - if ($hasMediaRelation) { - /** @var \PhpOffice\PhpWord\Element\Image $element Type hint */ - $image = ($elementName == 'Image') ? $element : null; - $rId = Media::addElement($mediaContainer, strtolower($elementName), $source, $image); - $element->setRelationId($rId); - } - - // Set relation Id for icon of object element - if ($elementName == 'Object') { - /** @var \PhpOffice\PhpWord\Element\Object $element Type hint */ - $rIdIcon = Media::addElement($mediaContainer, 'image', $element->getIcon(), new Image($element->getIcon())); - $element->setImageRelationId($rIdIcon); - } - - // Set relation Id for elements that will be registered in the Collection subnamespaces - if ($hasOtherRelation && $this->phpWord instanceof PhpWord) { - $addMethod = "add{$elementName}"; - $rId = $this->phpWord->$addMethod($element); - $element->setRelationId($rId); - } - } - /** * Check if a method is allowed for the current container * @@ -254,6 +197,9 @@ abstract class AbstractContainer extends AbstractElement 'Footnote' => array('Section', 'TextRun', 'Cell'), 'Endnote' => array('Section', 'TextRun', 'Cell'), 'PreserveText' => array('Header', 'Footer', 'Cell'), + 'Title' => array('Section'), + 'TOC' => array('Section'), + 'PageBreak' => array('Section'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer @@ -284,24 +230,6 @@ abstract class AbstractContainer extends AbstractElement return true; } - /** - * Return media element (image, object, link) container name - * - * @return string section|headerx|footerx|footnote|endnote - */ - private function getMediaContainer() - { - $partName = $this->container; - if (in_array($partName, array('Cell', 'TextRun', 'TextBox', 'ListItemRun'))) { - $partName = $this->getDocPart(); - } - if ($partName == 'Header' || $partName == 'Footer') { - $partName .= $this->getDocPartId(); - } - - return strtolower($partName); - } - /** * Add memory image element * diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index c8e574b7..623f6bfb 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style; @@ -42,7 +43,7 @@ abstract class AbstractElement protected $sectionId; /** - * Document part type: section|header|footer + * Document part type: Section|Header|Footer|Footnote|Endnote * * Used by textrun and cell container to determine where the element is * located because it will affect the availability of other element, @@ -93,6 +94,27 @@ abstract class AbstractElement */ private $nestedLevel = 0; + /** + * Parent container type + * + * @var string + */ + private $parentContainer; + + /** + * Has media relation flag; true for Link, Image, and Object + * + * @var bool + */ + protected $mediaRelation = false; + + /** + * Is part of collection; true for Title, Footnote, and Endnote + * + * @var bool + */ + protected $collectionRelation = false; + /** * Get PhpWord * @@ -155,6 +177,21 @@ abstract class AbstractElement return $this->docPartId; } + /** + * Return media element (image, object, link) container name + * + * @return string section|headerx|footerx|footnote|endnote + */ + private function getMediaPart() + { + $mediaPart = $this->docPart; + if ($mediaPart == 'Header' || $mediaPart == 'Footer') { + $mediaPart .= $this->docPartId; + } + + return strtolower($mediaPart); + } + /** * Get element index * @@ -224,13 +261,74 @@ abstract class AbstractElement } /** - * Set nested level + * Set parent container * - * @param int $value + * Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell) + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $container */ - public function setNestedLevel($value) + public function setParentContainer(AbstractElement $container) { - $this->nestedLevel = $value; + $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1); + + // Set nested level + $this->nestedLevel = $container->getNestedLevel(); + if ($this->parentContainer == 'Cell') { + $this->nestedLevel++; + } + + // Set phpword + $phpWord = $container->getPhpWord(); + $this->setPhpWord($phpWord); + + // Set doc part + if (!$this instanceof Footnote) { + $this->setDocPart($container->getDocPart(), $container->getDocPartId()); + } + + $this->setMediaRelation(); + $this->setCollectionRelation(); + } + + /** + * Set relation Id for media elements (link, image, object; legacy of OOXML) + * + * - Image element needs to be passed to Media object + * - Icon needs to be set for Object element + */ + private function setMediaRelation() + { + if ($this->mediaRelation === false) { + return; + } + + $mediaPart = $this->getMediaPart(); + $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1); + + /** @var \PhpOffice\PhpWord\Element\Image $this Type hint */ + $source = $this->getSource(); + $image = ($elementName == 'Image') ? $this : null; + $rId = Media::addElement($mediaPart, strtolower($elementName), $source, $image); + $this->setRelationId($rId); + + if ($elementName == 'Object') { + /** @var \PhpOffice\PhpWord\Element\Object $this Type hint */ + $rId = Media::addElement($mediaPart, 'image', $this->getIcon(), new Image($this->getIcon())); + $this->setImageRelationId($rId); + } + } + + /** + * Set relation Id for elements that will be registered in the Collection subnamespaces + */ + private function setCollectionRelation() + { + if ($this->collectionRelation === true && $this->phpWord instanceof PhpWord) { + $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1); + $addMethod = "add{$elementName}"; + $rId = $this->phpWord->$addMethod($this); + $this->setRelationId($rId); + } } /** diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 76311c6b..82bcd88f 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -36,6 +36,13 @@ class Footnote extends AbstractContainer */ protected $paragraphStyle; + /** + * Is part of collection; true for Title, Footnote, and Endnote + * + * @var bool + */ + protected $collectionRelation = true; + /** * Create new instance * @@ -44,6 +51,7 @@ class Footnote extends AbstractContainer public function __construct($paragraphStyle = null) { $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->setDocPart($this->container); } /** diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index a1cb8250..3d6a5545 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -111,6 +111,13 @@ class Image extends AbstractElement */ private $mediaIndex; + /** + * Has media relation flag; true for Link, Image, and Object + * + * @var bool + */ + protected $mediaRelation = true; + /** * Create new image element * diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 3ffe58d4..d962a3b5 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -27,11 +27,11 @@ use PhpOffice\PhpWord\Style\Paragraph; class Link extends AbstractElement { /** - * Link target + * Link source * * @var string */ - private $target; + private $source; /** * Link text @@ -54,19 +54,25 @@ class Link extends AbstractElement */ private $paragraphStyle; + /** + * Has media relation flag; true for Link, Image, and Object + * + * @var bool + */ + protected $mediaRelation = true; /** * Create a new Link Element * - * @param string $target + * @param string $source * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle */ - public function __construct($target, $text = null, $fontStyle = null, $paragraphStyle = null) + public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null) { - $this->target = String::toUTF8($target); - $this->text = is_null($text) ? $this->target : String::toUTF8($text); + $this->source = String::toUTF8($source); + $this->text = is_null($text) ? $this->source : String::toUTF8($text); $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); @@ -74,13 +80,13 @@ class Link extends AbstractElement } /** - * Get link target + * Get link source * * @return string */ - public function getTarget() + public function getSource() { - return $this->target; + return $this->source; } /** @@ -113,6 +119,18 @@ class Link extends AbstractElement return $this->paragraphStyle; } + /** + * Get link target + * + * @return string + * @deprecated 0.12.0 + * @codeCoverageIgnore + */ + public function getTarget() + { + return $this->source; + } + /** * Get Link source * @@ -122,7 +140,7 @@ class Link extends AbstractElement */ public function getLinkSrc() { - return $this->getTarget(); + return $this->getSource(); } /** diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index a63c1869..ca3ecdf1 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -53,6 +53,13 @@ class Object extends AbstractElement */ private $imageRelationId; + /** + * Has media relation flag; true for Link, Image, and Object + * + * @var bool + */ + protected $mediaRelation = true; + /** * Create a new Ole-Object Element * diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index d7dcea34..acbb75dc 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -69,9 +69,7 @@ class Row extends AbstractElement public function addCell($width = null, $style = null) { $cell = new Cell($width, $style); - $cell->setDocPart($this->getDocPart(), $this->getDocPartId()); - $cell->setPhpWord($this->phpWord); - $cell->setNestedLevel($this->getNestedLevel()); + $cell->setParentContainer($this); $this->cells[] = $cell; return $cell; diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index b7cee6a2..6fc63332 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -92,40 +92,6 @@ class Section extends AbstractContainer return $this->settings; } - /** - * Add a Title Element - * - * @param string $text - * @param int $depth - * @return \PhpOffice\PhpWord\Element\Title - */ - public function addTitle($text, $depth = 1) - { - return $this->addElement('Title', $text, $depth); - } - - /** - * Add a PageBreak Element - */ - public function addPageBreak() - { - return $this->addElement('PageBreak'); - } - - /** - * Add a Table-of-Contents Element - * - * @param mixed $fontStyle - * @param mixed $tocStyle - * @param integer $minDepth - * @param integer $maxDepth - * @return \PhpOffice\PhpWord\Element\TOC - */ - public function addTOC($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9) - { - return $this->addElement('TOC', $fontStyle, $tocStyle, $minDepth, $maxDepth); - } - /** * Add header * diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index ace63460..2d59073e 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -65,9 +65,7 @@ class Table extends AbstractElement public function addRow($height = null, $style = null) { $row = new Row($height, $style); - $row->setDocPart($this->getDocPart(), $this->getDocPartId()); - $row->setPhpWord($this->phpWord); - $row->setNestedLevel($this->getNestedLevel()); + $row->setParentContainer($this); $this->rows[] = $row; return $row; diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index d5206879..a4faeb70 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -46,6 +46,13 @@ class Title extends AbstractElement */ private $style; + /** + * Is part of collection; true for Title, Footnote, and Endnote + * + * @var bool + */ + protected $collectionRelation = true; + /** * Create a new Title Element * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index a7261d6d..ac26dee5 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -483,8 +483,8 @@ abstract class AbstractPart $style = true; } elseif ($method == self::READ_FALSE) { $style = false; - } elseif ($method == self::READ_EQUAL && $attributeValue == $expected) { - $style = true; + } elseif ($method == self::READ_EQUAL) { + $style = $attributeValue == $expected; } return $style; diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index d1256eb0..4e99810c 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -37,7 +37,7 @@ class Link extends Text $content = ''; $content .= $this->writeOpening(); - $content .= "element->getTarget()}\">{$this->element->getText()}"; + $content .= "element->getSource()}\">{$this->element->getText()}"; $content .= $this->writeClosing(); return $content; diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 79d3aa24..adb64f85 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -41,7 +41,7 @@ class Link extends AbstractElement $xmlWriter->startElement('text:a'); $xmlWriter->writeAttribute('xlink:type', 'simple'); - $xmlWriter->writeAttribute('xlink:href', $element->getTarget()); + $xmlWriter->writeAttribute('xlink:href', $element->getSource()); $xmlWriter->writeRaw($element->getText()); $xmlWriter->endElement(); // text:a diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index 22b08588..adbc7976 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -39,7 +39,7 @@ class Link extends AbstractElement $content = ''; $content .= $this->writeOpening(); - $content .= '{\field {\*\fldinst {HYPERLINK "' . $this->element->getTarget() . '"}}{\\fldrslt {'; + $content .= '{\field {\*\fldinst {HYPERLINK "' . $this->element->getSource() . '"}}{\\fldrslt {'; $content .= $this->writeFontStyle(); $content .= $this->writeText($this->element->getText()); $content .= '}}}'; diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 73673f05..6eb38dc2 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -64,8 +64,10 @@ class Font extends AbstractStyle $xmlWriter->startElement('w:rPr'); // Style name - $styleName = $style->getStyleName(); - $xmlWriter->writeElementIf(!is_null($styleName), 'w:rStyle', 'w:val', $styleName); + if ($this->isInline === true) { + $styleName = $style->getStyleName(); + $xmlWriter->writeElementIf($styleName !== null, 'w:rStyle', 'w:val', $styleName); + } // Font name/family $font = $style->getName(); diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 4ccba00f..f8d6cf1e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -83,7 +83,9 @@ class Paragraph extends AbstractStyle } // Style name - $xmlWriter->writeElementIf($styles['name'] !== null, 'w:pStyle', 'w:val', $styles['name']); + if ($this->isInline === true) { + $xmlWriter->writeElementIf($styles['name'] !== null, 'w:pStyle', 'w:val', $styles['name']); + } // Alignment $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $styles['alignment']))); diff --git a/tests/PhpWord/Tests/Element/LinkTest.php b/tests/PhpWord/Tests/Element/LinkTest.php index 0e582b13..ada6a36a 100644 --- a/tests/PhpWord/Tests/Element/LinkTest.php +++ b/tests/PhpWord/Tests/Element/LinkTest.php @@ -36,8 +36,8 @@ class LinkTest extends \PHPUnit_Framework_TestCase $oLink = new Link('http://www.google.com'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); - $this->assertEquals($oLink->getTarget(), 'http://www.google.com'); - $this->assertEquals($oLink->getText(), $oLink->getTarget()); + $this->assertEquals($oLink->getSource(), 'http://www.google.com'); + $this->assertEquals($oLink->getText(), $oLink->getSource()); $this->assertEquals($oLink->getFontStyle(), null); $this->assertEquals($oLink->getParagraphStyle(), null); } @@ -55,7 +55,7 @@ class LinkTest extends \PHPUnit_Framework_TestCase ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); - $this->assertEquals($oLink->getTarget(), 'http://www.google.com'); + $this->assertEquals($oLink->getSource(), 'http://www.google.com'); $this->assertEquals($oLink->getText(), 'Search Engine'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Element/ListItemRunTest.php b/tests/PhpWord/Tests/Element/ListItemRunTest.php index 37d679f9..7bb0c25d 100644 --- a/tests/PhpWord/Tests/Element/ListItemRunTest.php +++ b/tests/PhpWord/Tests/Element/ListItemRunTest.php @@ -131,7 +131,7 @@ class ListItemRunTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals($element->getTarget(), 'http://www.google.fr'); + $this->assertEquals($element->getSource(), 'http://www.google.fr'); } /** @@ -144,7 +144,7 @@ class ListItemRunTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals($element->getTarget(), 'http://www.google.fr'); + $this->assertEquals($element->getSource(), 'http://www.google.fr'); $this->assertEquals($element->getText(), 'ééé'); } diff --git a/tests/PhpWord/Tests/Element/TextRunTest.php b/tests/PhpWord/Tests/Element/TextRunTest.php index 870214dd..de62a920 100644 --- a/tests/PhpWord/Tests/Element/TextRunTest.php +++ b/tests/PhpWord/Tests/Element/TextRunTest.php @@ -99,7 +99,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getTarget(), 'http://www.google.fr'); + $this->assertEquals($element->getSource(), 'http://www.google.fr'); } /** @@ -112,7 +112,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getTarget(), 'http://www.google.fr'); + $this->assertEquals($element->getSource(), 'http://www.google.fr'); $this->assertEquals($element->getText(), 'ééé'); } diff --git a/tests/PhpWord/Tests/Style/SectionTest.php b/tests/PhpWord/Tests/Style/SectionTest.php index de582948..8e8c1e87 100644 --- a/tests/PhpWord/Tests/Style/SectionTest.php +++ b/tests/PhpWord/Tests/Style/SectionTest.php @@ -37,6 +37,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals('portrait', $oSettings->getOrientation()); $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW()); $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH()); + $this->assertEquals('A4', $oSettings->getPaperSize()); $oSettings->setSettingValue('orientation', 'landscape'); $this->assertEquals('landscape', $oSettings->getOrientation()); From a9c9c21d3bf0b4b7590fbae2ab98b9fd6e3b9b44 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 03:38:53 +0700 Subject: [PATCH 252/326] Fix Travis test error --- src/PhpWord/Element/AbstractContainer.php | 3 ++- src/PhpWord/Element/AbstractElement.php | 17 +++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 64c4b768..5093d3f4 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -76,7 +76,8 @@ abstract class AbstractContainer extends AbstractElement { $elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', - 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape'); + 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', + 'Title', 'TOC', 'PageBreak'); $functions = array(); for ($i = 0; $i < count($elements); $i++) { $functions[$i] = 'add' . $elements[$i]; diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 623f6bfb..4110351d 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -298,22 +298,23 @@ abstract class AbstractElement */ private function setMediaRelation() { - if ($this->mediaRelation === false) { + if (!$this instanceof Link && !$this instanceof Image && !$this instanceof Object) { return; } - $mediaPart = $this->getMediaPart(); $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1); - - /** @var \PhpOffice\PhpWord\Element\Image $this Type hint */ + $mediaPart = $this->getMediaPart(); $source = $this->getSource(); - $image = ($elementName == 'Image') ? $this : null; + $image = null; + if ($this instanceof Image) { + $image = $this; + } $rId = Media::addElement($mediaPart, strtolower($elementName), $source, $image); $this->setRelationId($rId); - if ($elementName == 'Object') { - /** @var \PhpOffice\PhpWord\Element\Object $this Type hint */ - $rId = Media::addElement($mediaPart, 'image', $this->getIcon(), new Image($this->getIcon())); + if ($this instanceof Object) { + $icon = $this->getIcon(); + $rId = Media::addElement($mediaPart, 'image', $icon, new Image($icon)); $this->setImageRelationId($rId); } } From 63d53ac910bb599a77e2fb699da4ea3f23df2978 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 16:44:46 +0700 Subject: [PATCH 253/326] Use section "style" instead of "settings" for consistency --- CHANGELOG.md | 1 + docs/containers.rst | 20 +++---- docs/general.rst | 2 +- docs/src/documentation.md | 22 +++---- src/PhpWord/Element/AbstractElement.php | 4 +- src/PhpWord/Element/Cell.php | 2 +- src/PhpWord/Element/Endnote.php | 2 +- src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Element/Line.php | 2 +- src/PhpWord/Element/Link.php | 4 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/ListItemRun.php | 4 +- src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PreserveText.php | 4 +- src/PhpWord/Element/Row.php | 2 +- src/PhpWord/Element/Section.php | 59 ++++++++++++------- src/PhpWord/Element/Shape.php | 2 +- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/TextBox.php | 2 +- src/PhpWord/Element/TextRun.php | 2 +- src/PhpWord/PhpWord.php | 6 +- src/PhpWord/Reader/Word2007/Document.php | 6 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 +- src/PhpWord/Writer/RTF/Part/Header.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- tests/PhpWord/Tests/Element/SectionTest.php | 12 ++-- .../Writer/Word2007/Part/DocumentTest.php | 10 ++-- 29 files changed, 103 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7acfecee..19d99348 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme ### Deprecated - `Element\Link::getTarget()` replaced by `Element\Link::getSource()` +- `Element\Section::getSettings()` and `Element\Section::setSettings()` replaced by `Element\Section::getStyle()` and `Element\Section::setStyle()` ### Miscellaneous diff --git a/docs/containers.rst b/docs/containers.rst index 30566df6..df04e658 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -32,7 +32,7 @@ section. Example: Section settings ~~~~~~~~~~~~~~~~ -Below are the available settings for section: +Below are the available styles for section: - ``orientation`` Page orientation, i.e. 'portrait' (default) or 'landscape' @@ -56,8 +56,8 @@ Below are the available settings for section: - ``breakType`` Section break type (nextPage, nextColumn, continuous, evenPage, oddPage) -The following two settings are automatically set by the use of the -``orientation`` setting. You can alter them but that's not recommended. +The following two styles are automatically set by the use of the +``orientation`` style. You can alter them but that's not recommended. - ``pageSizeW`` Page width in twips - ``pageSizeH`` Page height in twips @@ -66,7 +66,7 @@ Page number ~~~~~~~~~~~ You can change a section page number by using the ``pageNumberingStart`` -property of the section. +style of the section. .. code-block:: php @@ -75,13 +75,13 @@ property of the section. // Method 2 $section = $phpWord->addSection(); - $section->getSettings()->setPageNumberingStart(1); + $section->getStyle()->setPageNumberingStart(1); Multicolumn ~~~~~~~~~~~ You can change a section layout to multicolumn (like in a newspaper) by -using the ``breakType`` and ``colsNum`` property of the section. +using the ``breakType`` and ``colsNum`` style of the section. .. code-block:: php @@ -90,14 +90,14 @@ using the ``breakType`` and ``colsNum`` property of the section. // Method 2 $section = $phpWord->addSection(); - $section->getSettings()->setBreakType('continuous'); - $section->getSettings()->setColsNum(2); + $section->getStyle()->setBreakType('continuous'); + $section->getStyle()->setColsNum(2); ### Line numbering You can apply line numbering to a section by using the ``lineNumbering`` -property of the section. +style of the section. .. code-block:: php @@ -106,7 +106,7 @@ property of the section. // Method 2 $section = $phpWord->addSection(); - $section->getSettings()->setLineNumbering(array()); + $section->getStyle()->setLineNumbering(array()); Below are the properties of the line numbering style. diff --git a/docs/general.rst b/docs/general.rst index f08e29ba..270608f7 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -138,7 +138,7 @@ points to twips. ); $section = $phpWord->addSection(); - $sectionStyle = $section->getSettings(); + $sectionStyle = $section->getStyle(); // half inch left margin $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); // 2 cm right margin diff --git a/docs/src/documentation.md b/docs/src/documentation.md index e9716401..e0f00dac 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -304,7 +304,7 @@ $phpWord->addParagraphStyle('My Style', array( ); $section = $phpWord->addSection(); -$sectionStyle = $section->getSettings(); +$sectionStyle = $section->getStyle(); // half inch left margin $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); // 2 cm right margin @@ -333,9 +333,9 @@ $sectionSettings = array( ); ``` -### Section settings +### Section style -Below are the available settings for section: +Below are the available styles for section: - `orientation` Page orientation, i.e. 'portrait' (default) or 'landscape' - `marginTop` Page margin top in twips @@ -357,14 +357,14 @@ Below are the available settings for section: - `colsSpace` Spacing between columns - `breakType` Section break type (nextPage, nextColumn, continuous, evenPage, oddPage) -The following two settings are automatically set by the use of the `orientation` setting. You can alter them but that's not recommended. +The following two styles are automatically set by the use of the `orientation` style. You can alter them but that's not recommended. - `pageSizeW` Page width in twips - `pageSizeH` Page height in twips ### Page number -You can change a section page number by using the `pageNumberingStart` property of the section. +You can change a section page number by using the `pageNumberingStart` style of the section. ```php // Method 1 @@ -372,12 +372,12 @@ $section = $phpWord->addSection(array('pageNumberingStart' => 1)); // Method 2 $section = $phpWord->addSection(); -$section->getSettings()->setPageNumberingStart(1); +$section->getStyle()->setPageNumberingStart(1); ``` ### Multicolumn -You can change a section layout to multicolumn (like in a newspaper) by using the `breakType` and `colsNum` property of the section. +You can change a section layout to multicolumn (like in a newspaper) by using the `breakType` and `colsNum` style of the section. ```php // Method 1 @@ -385,13 +385,13 @@ $section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => // Method 2 $section = $phpWord->addSection(); -$section->getSettings()->setBreakType('continuous'); -$section->getSettings()->setColsNum(2); +$section->getStyle()->setBreakType('continuous'); +$section->getStyle()->setColsNum(2); ``` ### Line numbering -You can apply line numbering to a section by using the `lineNumbering` property of the section. +You can apply line numbering to a section by using the `lineNumbering` style of the section. ```php // Method 1 @@ -399,7 +399,7 @@ $section = $phpWord->addSection(array('lineNumbering' => array())); // Method 2 $section = $phpWord->addSection(); -$section->getSettings()->setLineNumbering(array()); +$section->getStyle()->setLineNumbering(array()); ``` Below are the properties of the line numbering style. diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 4110351d..fe133fdd 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -343,14 +343,14 @@ abstract class AbstractElement } /** - * Set style value + * Set new style value * * @param mixed $styleObject Style object * @param mixed $styleValue Style value * @param bool $returnObject Always return object * @return mixed */ - protected function setStyle($styleObject, $styleValue = null, $returnObject = false) + protected function setNewStyle($styleObject, $styleValue = null, $returnObject = false) { if (!is_null($styleValue) && is_array($styleValue)) { $styleObject->setStyleByArray($styleValue); diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index ea49bc7b..cac37a78 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -52,7 +52,7 @@ class Cell extends AbstractContainer public function __construct($width = null, $style = null) { $this->width = $width; - $this->style = $this->setStyle(new CellStyle(), $style, true); + $this->style = $this->setNewStyle(new CellStyle(), $style, true); } /** diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 20278898..10000555 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -38,6 +38,6 @@ class Endnote extends Footnote */ public function __construct($paragraphStyle = null) { - $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); } } diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 82bcd88f..e263933c 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -50,7 +50,7 @@ class Footnote extends AbstractContainer */ public function __construct($paragraphStyle = null) { - $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->setDocPart($this->container); } diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 3d6a5545..532905f4 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -131,7 +131,7 @@ class Image extends AbstractElement { $this->source = $source; $this->setIsWatermark($watermark); - $this->style = $this->setStyle(new ImageStyle(), $style, true); + $this->style = $this->setNewStyle(new ImageStyle(), $style, true); $this->checkImage($source); } diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 4acca8ed..b76ac4fb 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -38,7 +38,7 @@ class Line extends AbstractElement */ public function __construct($style = null) { - $this->style = $this->setStyle(new LineStyle(), $style); + $this->style = $this->setNewStyle(new LineStyle(), $style); } /** diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index d962a3b5..4b00dc90 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -73,8 +73,8 @@ class Link extends AbstractElement { $this->source = String::toUTF8($source); $this->text = is_null($text) ? $this->source : String::toUTF8($text); - $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); - $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); + $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); return $this; } diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 59bd8391..4cb8d339 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -64,7 +64,7 @@ class ListItem extends AbstractElement if (!is_null($listStyle) && is_string($listStyle)) { $this->style = new ListItemStyle($listStyle); } else { - $this->style = $this->setStyle(new ListItemStyle(), $listStyle, true); + $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); } } diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index fb219f91..82c6f1ab 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -59,9 +59,9 @@ class ListItemRun extends TextRun if (!is_null($listStyle) && is_string($listStyle)) { $this->style = new ListItemStyle($listStyle); } else { - $this->style = $this->setStyle(new ListItemStyle(), $listStyle, true); + $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); } - $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); } /** diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index ca3ecdf1..ae279ab0 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -79,7 +79,7 @@ class Object extends AbstractElement } $this->source = $source; - $this->style = $this->setStyle(new ImageStyle(), $style, true); + $this->style = $this->setNewStyle(new ImageStyle(), $style, true); $this->icon = realpath(__DIR__ . "/../resources/{$ext}.png"); return $this; diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 100385c9..44aef3b4 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -58,8 +58,8 @@ class PreserveText extends AbstractElement */ public function __construct($text = null, $fontStyle = null, $paragraphStyle = null) { - $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); - $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); + $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->text = String::toUTF8($text); $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index acbb75dc..e2df6325 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -56,7 +56,7 @@ class Row extends AbstractElement public function __construct($height = null, $style = null) { $this->height = $height; - $this->style = $this->setStyle(new RowStyle(), $style, true); + $this->style = $this->setNewStyle(new RowStyle(), $style, true); } /** diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 6fc63332..33c69795 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Style\Section as SectionSettings; +use PhpOffice\PhpWord\Style\Section as SectionStyle; /** * Section @@ -31,11 +31,11 @@ class Section extends AbstractContainer protected $container = 'Section'; /** - * Section settings + * Section style * * @var \PhpOffice\PhpWord\Style\Section */ - private $settings; + private $style; /** * Section headers, indexed from 1, not zero @@ -55,41 +55,36 @@ class Section extends AbstractContainer * Create new instance * * @param int $sectionCount - * @param array $settings + * @param array $style */ - public function __construct($sectionCount, $settings = null) + public function __construct($sectionCount, $style = null) { $this->sectionId = $sectionCount; $this->setDocPart($this->container, $this->sectionId); - $this->settings = new SectionSettings(); - $this->setSettings($settings); + $this->style = new SectionStyle(); + $this->setStyle($style); } /** - * Set section settings + * Set section style * - * @param array $settings + * @param array $style */ - public function setSettings($settings = null) + public function setStyle($style = null) { - if (!is_null($settings) && is_array($settings)) { - foreach ($settings as $key => $value) { - if (is_null($value)) { - continue; - } - $this->settings->setSettingValue($key, $value); - } + if (!is_null($style) && is_array($style)) { + $this->style->setStyleByArray($style); } } /** - * Get Section Settings + * Get section style * * @return \PhpOffice\PhpWord\Style\Section */ - public function getSettings() + public function getStyle() { - return $this->settings; + return $this->style; } /** @@ -184,6 +179,30 @@ class Section extends AbstractContainer } + /** + * Set section style + * + * @param array $settings + * @deprecated 0.12.0 + * @codeCoverageIgnore + */ + public function setSettings($settings = null) + { + $this->setStyle($settings); + } + + /** + * Get section style + * + * @return \PhpOffice\PhpWord\Style\Section + * @deprecated 0.12.0 + * @codeCoverageIgnore + */ + public function getSettings() + { + return $this->getStyle(); + } + /** * Create header * diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index 9b3aae4f..a7a96d18 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -49,7 +49,7 @@ class Shape extends AbstractElement public function __construct($type, $style = null) { $this->setType($type); - $this->style = $this->setStyle(new ShapeStyle(), $style); + $this->style = $this->setNewStyle(new ShapeStyle(), $style); } /** diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 2d59073e..5e14d6bc 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -52,7 +52,7 @@ class Table extends AbstractElement */ public function __construct($style = null) { - $this->style = $this->setStyle(new TableStyle(), $style); + $this->style = $this->setNewStyle(new TableStyle(), $style); } /** diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index 06c95181..d929bf35 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -45,7 +45,7 @@ class TextBox extends AbstractContainer */ public function __construct($style = null) { - $this->style = $this->setStyle(new TextBoxStyle(), $style); + $this->style = $this->setNewStyle(new TextBoxStyle(), $style); } /** diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 75837104..c356cfa8 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -43,7 +43,7 @@ class TextRun extends AbstractContainer */ public function __construct($paragraphStyle = null) { - $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); } /** diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index c54faa36..e06080c1 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -121,12 +121,12 @@ class PhpWord /** * Create new section * - * @param array $settings + * @param array $style * @return \PhpOffice\PhpWord\Element\Section */ - public function addSection($settings = null) + public function addSection($style = null) { - $section = new Section(count($this->sections) + 1, $settings); + $section = new Section(count($this->sections) + 1, $style); $section->setPhpWord($this); $this->sections[] = $section; diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index be804531..02084189 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -175,8 +175,8 @@ class Document extends AbstractPart */ private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section) { - $settings = $this->readSectionStyle($xmlReader, $node); - $section->setSettings($settings); - $this->readHeaderFooter($settings, $section); + $style = $this->readSectionStyle($xmlReader, $node); + $section->setStyle($style); + $this->readHeaderFooter($style, $section); } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index f16937a0..51326210 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -168,7 +168,7 @@ class Content extends AbstractPart $paragraphStyleCount = 0; $fontStyleCount = 0; foreach ($sections as $section) { - $style = $section->getSettings(); + $style = $section->getStyle(); $style->setStyleName("Section{$section->getSectionId()}"); $this->autoStyles['Section'][] = $style; $this->getContainerStyle($section, $paragraphStyleCount, $fontStyleCount); diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 2f5c2f8e..f0a9b8f2 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -110,7 +110,7 @@ class Document extends AbstractPart $sections = $this->getParentWriter()->getPhpWord()->getSections(); foreach ($sections as $section) { - $styleWriter = new SectionStyleWriter($section->getSettings()); + $styleWriter = new SectionStyleWriter($section->getStyle()); $styleWriter->setParentWriter($this->getParentWriter()); $content .= $styleWriter->write(); diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 32debb06..4d8d3a27 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -193,7 +193,7 @@ class Header extends AbstractPart $sections = $phpWord->getSections(); foreach ($sections as $section) { $elements = $section->getElements(); - $this->registerBorderColor($section->getSettings()); + $this->registerBorderColor($section->getStyle()); foreach ($elements as $element) { if (method_exists($element, 'getFontStyle')) { $style = $element->getFontStyle(); diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 99570338..e6639511 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -128,7 +128,7 @@ class Document extends AbstractPart } // Section settings - $styleWriter = new SectionStyleWriter($xmlWriter, $section->getSettings()); + $styleWriter = new SectionStyleWriter($xmlWriter, $section->getStyle()); $styleWriter->write(); $xmlWriter->endElement(); // w:sectPr diff --git a/tests/PhpWord/Tests/Element/SectionTest.php b/tests/PhpWord/Tests/Element/SectionTest.php index af7595e2..853ebc5d 100644 --- a/tests/PhpWord/Tests/Element/SectionTest.php +++ b/tests/PhpWord/Tests/Element/SectionTest.php @@ -31,12 +31,12 @@ use PhpOffice\PhpWord\Style; class SectionTest extends \PHPUnit_Framework_TestCase { /** - * Get settings + * Get style */ - public function testGetSettings() + public function testGetStyle() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getSettings(), 'settings', new Section(0)); + $this->assertAttributeEquals($oSection->getStyle(), 'style', new Section(0)); } /** @@ -69,12 +69,12 @@ class SectionTest extends \PHPUnit_Framework_TestCase /** * Set settings */ - public function testSetSettings() + public function testSetStyle() { $expected = 'landscape'; $object = new Section(0); - $object->setSettings(array('orientation' => $expected, 'foo' => null)); - $this->assertEquals($expected, $object->getSettings()->getOrientation()); + $object->setStyle(array('orientation' => $expected, 'foo' => null)); + $this->assertEquals($expected, $object->getStyle()->getOrientation()); } /** diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index fd36db25..de5d63e8 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -45,11 +45,11 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $section = $phpWord->addSection(); $section->addHeader(); $section->addHeader('first'); - $settings = $section->getSettings(); - $settings->setLandscape(); - $settings->setPageNumberingStart(2); - $settings->setBorderSize(240); - $settings->setBreakType('nextPage'); + $style = $section->getStyle(); + $style->setLandscape(); + $style->setPageNumberingStart(2); + $style->setBorderSize(240); + $style->setBreakType('nextPage'); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType'); From 3197524343c3a60d24a268511f2c732b9dc4343b Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 17:10:02 +0700 Subject: [PATCH 254/326] Docs: Restructure documentation --- docs/conf.py | 4 +- docs/containers.rst | 46 +---- docs/elements.rst | 116 +------------ docs/index.rst | 3 +- docs/{setup.rst => installing.rst} | 0 docs/src/documentation.md | 258 +++++++++++++++-------------- docs/styles.rst | 137 +++++++++++++++ 7 files changed, 287 insertions(+), 277 deletions(-) rename docs/{setup.rst => installing.rst} (100%) create mode 100644 docs/styles.rst diff --git a/docs/conf.py b/docs/conf.py index f5c38581..de645350 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,14 +41,14 @@ master_doc = 'index' # General information about the project. project = u'PhpWord' -copyright = u'2014, Progi1984' +copyright = u'2014, PHPWord Contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.9.0' +version = '0.12.0' # The full version, including alpha/beta/rc tags. release = version diff --git a/docs/containers.rst b/docs/containers.rst index df04e658..f165a589 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -16,52 +16,19 @@ section, use the following code: .. code-block:: php - $section = $phpWord->addSection($sectionSettings); + $section = $phpWord->addSection($sectionStyle); -The ``$sectionSettings`` is an optional associative array that sets the +The ``$sectionStyle`` is an optional associative array that sets the section. Example: .. code-block:: php - $sectionSettings = array( + $sectionStyle = array( 'orientation' => 'landscape', 'marginTop' => 600, 'colsNum' => 2, ); -Section settings -~~~~~~~~~~~~~~~~ - -Below are the available styles for section: - -- ``orientation`` Page orientation, i.e. 'portrait' (default) or - 'landscape' -- ``marginTop`` Page margin top in twips -- ``marginLeft`` Page margin left in twips -- ``marginRight`` Page margin right in twips -- ``marginBottom`` Page margin bottom in twips -- ``borderTopSize`` Border top size in twips -- ``borderTopColor`` Border top color -- ``borderLeftSize`` Border left size in twips -- ``borderLeftColor`` Border left color -- ``borderRightSize`` Border right size in twips -- ``borderRightColor`` Border right color -- ``borderBottomSize`` Border bottom size in twips -- ``borderBottomColor`` Border bottom color -- ``headerHeight`` Spacing to top of header -- ``footerHeight`` Spacing to bottom of footer -- ``gutter`` Page gutter spacing -- ``colsNum`` Number of columns -- ``colsSpace`` Spacing between columns -- ``breakType`` Section break type (nextPage, nextColumn, continuous, - evenPage, oddPage) - -The following two styles are automatically set by the use of the -``orientation`` style. You can alter them but that's not recommended. - -- ``pageSizeW`` Page width in twips -- ``pageSizeH`` Page height in twips - Page number ~~~~~~~~~~~ @@ -93,8 +60,8 @@ using the ``breakType`` and ``colsNum`` style of the section. $section->getStyle()->setBreakType('continuous'); $section->getStyle()->setColsNum(2); - -### Line numbering +Line numbering +~~~~~~~~~~~~~~ You can apply line numbering to a section by using the ``lineNumbering`` style of the section. @@ -113,7 +80,8 @@ Below are the properties of the line numbering style. - ``start`` Line numbering starting value - ``increment`` Line number increments - ``distance`` Distance between text and line numbering in twip -- ``restart`` Line numbering restart setting continuous|newPage|newSection +- ``restart`` Line numbering restart setting + continuous\|newPage\|newSection Headers ------- diff --git a/docs/elements.rst b/docs/elements.rst index a3a81717..a01c9fd4 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -47,7 +47,7 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 19 | Line | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ -| 20 | Shapes | v | v | v | v | v | v | +| 20 | Shape | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -73,9 +73,6 @@ as follow: $section->addText($text, [$fontStyle], [$paragraphStyle]); $textrun = $section->addTextRun([$paragraphStyle]); -Text styles -~~~~~~~~~~~ - You can use the ``$fontStyle`` and ``$paragraphStyle`` variable to define text formatting. There are 2 options to style the inserted text elements, i.e. inline style by using array or defined style by adding @@ -106,47 +103,6 @@ Defined style examples: $phpWord->addParagraphStyle('pStyle', $paragraphStyle); $text = $section->addText('Hello world!', 'pStyle'); -Font style -^^^^^^^^^^ - -Available font styles: - -- ``name`` Font name, e.g. *Arial* -- ``size`` Font size, e.g. *20*, *22*, -- ``hint`` Font content type, *default*, *eastAsia*, or *cs* -- ``bold`` Bold, *true* or *false* -- ``italic`` Italic, *true* or *false* -- ``superScript`` Superscript, *true* or *false* -- ``subScript`` Subscript, *true* or *false* -- ``underline`` Underline, *dash*, *dotted*, etc. -- ``strikethrough`` Strikethrough, *true* or *false* -- ``doubleStrikethrough`` Double strikethrough, *true* or *false* -- ``color`` Font color, e.g. *FF0000* -- ``fgColor`` Font highlight color, e.g. *yellow*, *green*, *blue* -- ``bgColor`` Font background color, e.g. *FF0000* -- ``smallCaps`` Small caps, *true* or *false* -- ``allCaps`` All caps, *true* or *false* - -Paragraph style -^^^^^^^^^^^^^^^ - -Available paragraph styles: - -- ``align`` Paragraph alignment, *left*, *right* or *center* -- ``spaceBefore`` Space before paragraph -- ``spaceAfter`` Space after paragraph -- ``indent`` Indent by how much -- ``hanging`` Hanging by how much -- ``basedOn`` Parent style -- ``next`` Style for next paragraph -- ``widowControl`` Allow first/last line to display on a separate page, - *true* or *false* -- ``keepNext`` Keep paragraph with next paragraph, *true* or *false* -- ``keepLines`` Keep all lines on one page, *true* or *false* -- ``pageBreakBefore`` Start paragraph on next page, *true* or *false* -- ``lineHeight`` text line height, e.g. *1.0*, *1.5*, ect... -- ``tabs`` Set of custom tab stops - Titles ~~~~~~ @@ -209,9 +165,9 @@ Page breaks There are two ways to insert a page breaks, using the ``addPageBreak`` method or using the ``pageBreakBefore`` style of paragraph. -:: code-block:: php +.. code-block:: php - \\$section->addPageBreak(); + $section->addPageBreak(); Lists ----- @@ -254,23 +210,6 @@ You can also create your own numbering style by changing the $section->addListItem('List Item I.b', 1, null, 'multilevel'); $section->addListItem('List Item II', 0, null, 'multilevel'); -Level styles: - -- ``start`` Starting value -- ``format`` Numbering format - bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter -- ``restart`` Restart numbering level symbol -- ``suffix`` Content between numbering symbol and paragraph text - tab\|space\|nothing -- ``text`` Numbering level text e.g. %1 for nonbullet or bullet - character -- ``align`` Numbering symbol align left\|center\|right\|both -- ``left`` See paragraph style -- ``hanging`` See paragraph style -- ``tabPos`` See paragraph style -- ``font`` Font name -- ``hint`` See font style - Tables ------ @@ -296,34 +235,6 @@ Table style can be defined with ``addTableStyle``: $phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); $table = $section->addTable('myTable'); -Table, row, and cell styles -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Table styles: - -- ``width`` Table width in percent -- ``bgColor`` Background color, e.g. '9966CC' -- ``border(Top|Right|Bottom|Left)Size`` Border size in twips -- ``border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' -- ``cellMargin(Top|Right|Bottom|Left)`` Cell margin in twips - -Row styles: - -- ``tblHeader`` Repeat table row on every new page, *true* or *false* -- ``cantSplit`` Table row cannot break across pages, *true* or *false* -- ``exactHeight`` Row height is exact or at least - -Cell styles: - -- ``width`` Cell width in twips -- ``valign`` Vertical alignment, *top*, *center*, *both*, *bottom* -- ``textDirection`` Direction of text -- ``bgColor`` Background color, e.g. '9966CC' -- ``border(Top|Right|Bottom|Left)Size`` Border size in twips -- ``border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' -- ``gridSpan`` Number of columns spanned -- ``vMerge`` *restart* or *continue* - Cell span ~~~~~~~~~ @@ -370,19 +281,6 @@ Examples: $textrun = $section->addTextRun(); $textrun->addImage('http://php.net/logo.jpg'); -Image styles -~~~~~~~~~~~~ - -Available image styles: - -- ``width`` Width in pixels -- ``height`` Height in pixels -- ``align`` Image alignment, *left*, *right*, or *center* -- ``marginTop`` Top margin in inches, can be negative -- ``marginLeft`` Left margin in inches, can be negative -- ``wrappingStyle`` Wrapping style, *inline*, *square*, *tight*, - *behind*, or *infront* - Watermarks ~~~~~~~~~~ @@ -485,19 +383,19 @@ Checkbox elements can be added to sections or table cells by using Textboxes --------- -To be completed +To be completed. Fields ------ -To be completed +To be completed. Lines ----- -To be completed +To be completed. Shapes ------ -To be completed +To be completed. diff --git a/docs/index.rst b/docs/index.rst index fd3a3fa9..4f200cca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,10 +18,11 @@ Format (RTF). :maxdepth: 2 intro - setup + installing general containers elements + styles templates writersreaders recipes diff --git a/docs/setup.rst b/docs/installing.rst similarity index 100% rename from docs/setup.rst rename to docs/installing.rst diff --git a/docs/src/documentation.md b/docs/src/documentation.md index e0f00dac..c76ec1f2 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -37,6 +37,11 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [Fields](#fields) - [Lines](#lines) - [Shapes](#shapes) +- [Styles](#styles) + - [Section](#section) + - [Font](#font) + - [Paragraph](#paragraph) + - [Table](#table) - [Templates](#templates) - [Writers & readers](#writers-readers) - [OOXML](#ooxml) @@ -320,47 +325,19 @@ Containers are objects where you can put elements (texts, lists, tables, etc). T Every visible element in word is placed inside of a section. To create a section, use the following code: ```php -$section = $phpWord->addSection($sectionSettings); +$section = $phpWord->addSection($sectionStyle); ``` -The `$sectionSettings` is an optional associative array that sets the section. Example: +The `$sectionStyle` is an optional associative array that sets the section. Example: ```php -$sectionSettings = array( +$sectionStyle = array( 'orientation' => 'landscape', 'marginTop' => 600, 'colsNum' => 2, ); ``` -### Section style - -Below are the available styles for section: - -- `orientation` Page orientation, i.e. 'portrait' (default) or 'landscape' -- `marginTop` Page margin top in twips -- `marginLeft` Page margin left in twips -- `marginRight` Page margin right in twips -- `marginBottom` Page margin bottom in twips -- `borderTopSize` Border top size in twips -- `borderTopColor` Border top color -- `borderLeftSize` Border left size in twips -- `borderLeftColor` Border left color -- `borderRightSize` Border right size in twips -- `borderRightColor` Border right color -- `borderBottomSize` Border bottom size in twips -- `borderBottomColor` Border bottom color -- `headerHeight` Spacing to top of header -- `footerHeight` Spacing to bottom of footer -- `gutter` Page gutter spacing -- `colsNum` Number of columns -- `colsSpace` Spacing between columns -- `breakType` Section break type (nextPage, nextColumn, continuous, evenPage, oddPage) - -The following two styles are automatically set by the use of the `orientation` style. You can alter them but that's not recommended. - -- `pageSizeW` Page width in twips -- `pageSizeH` Page height in twips ### Page number @@ -485,8 +462,6 @@ $section->addText($text, [$fontStyle], [$paragraphStyle]); $textrun = $section->addTextRun([$paragraphStyle]); ``` -### Text styles - You can use the `$fontStyle` and `$paragraphStyle` variable to define text formatting. There are 2 options to style the inserted text elements, i.e. inline style by using array or defined style by adding style definition. Inline style examples: @@ -514,44 +489,6 @@ $phpWord->addParagraphStyle('pStyle', $paragraphStyle); $text = $section->addText('Hello world!', 'pStyle'); ``` -#### Font style - -Available font styles: - -- `name` Font name, e.g. *Arial* -- `size` Font size, e.g. *20*, *22*, -- `hint` Font content type, *default*, *eastAsia*, or *cs* -- `bold` Bold, *true* or *false* -- `italic` Italic, *true* or *false* -- `superScript` Superscript, *true* or *false* -- `subScript` Subscript, *true* or *false* -- `underline` Underline, *dash*, *dotted*, etc. -- `strikethrough` Strikethrough, *true* or *false* -- `doubleStrikethrough` Double strikethrough, *true* or *false* -- `color` Font color, e.g. *FF0000* -- `fgColor` Font highlight color, e.g. *yellow*, *green*, *blue* -- `bgColor` Font background color, e.g. *FF0000* -- `smallCaps` Small caps, *true* or *false* -- `allCaps` All caps, *true* or *false* - -#### Paragraph style - -Available paragraph styles: - -- `align` Paragraph alignment, *left*, *right* or *center* -- `spaceBefore` Space before paragraph -- `spaceAfter` Space after paragraph -- `indent` Indent by how much -- `hanging` Hanging by how much -- `basedOn` Parent style -- `next` Style for next paragraph -- `widowControl` Allow first/last line to display on a separate page, *true* or *false* -- `keepNext` Keep paragraph with next paragraph, *true* or *false* -- `keepLines` Keep all lines on one page, *true* or *false* -- `pageBreakBefore` Start paragraph on next page, *true* or *false* -- `lineHeight` text line height, e.g. *1.0*, *1.5*, ect... -- `tabs` Set of custom tab stops - ### Titles If you want to structure your document or build table of contents, you need titles or headings. To add a title to the document, use the `addTitleStyle` and `addTitle` method. @@ -602,9 +539,9 @@ $section->addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]); There are two ways to insert a page breaks, using the `addPageBreak` method or using the `pageBreakBefore` style of paragraph. -:: code-block:: php - -> \$section-\>addPageBreak(); +```php +$section->addPageBreak(); +``` ## Lists @@ -643,20 +580,6 @@ $section->addListItem('List Item I.b', 1, null, 'multilevel'); $section->addListItem('List Item II', 0, null, 'multilevel'); ``` -Level styles: - -- `start` Starting value -- `format` Numbering format bullet|decimal|upperRoman|lowerRoman|upperLetter|lowerLetter -- `restart` Restart numbering level symbol -- `suffix` Content between numbering symbol and paragraph text tab|space|nothing -- `text` Numbering level text e.g. %1 for nonbullet or bullet character -- `align` Numbering symbol align left|center|right|both -- `left` See paragraph style -- `hanging` See paragraph style -- `tabPos` See paragraph style -- `font` Font name -- `hint` See font style - ## Tables To add tables, rows, and cells, use the `addTable`, `addRow`, and `addCell` methods: @@ -680,33 +603,6 @@ $phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); $table = $section->addTable('myTable'); ``` -### Table, row, and cell styles - -Table styles: - -- `width` Table width in percent -- `bgColor` Background color, e.g. '9966CC' -- `border(Top|Right|Bottom|Left)Size` Border size in twips -- `border(Top|Right|Bottom|Left)Color` Border color, e.g. '9966CC' -- `cellMargin(Top|Right|Bottom|Left)` Cell margin in twips - -Row styles: - -- `tblHeader` Repeat table row on every new page, *true* or *false* -- `cantSplit` Table row cannot break across pages, *true* or *false* -- `exactHeight` Row height is exact or at least - -Cell styles: - -- `width` Cell width in twips -- `valign` Vertical alignment, *top*, *center*, *both*, *bottom* -- `textDirection` Direction of text -- `bgColor` Background color, e.g. '9966CC' -- `border(Top|Right|Bottom|Left)Size` Border size in twips -- `border(Top|Right|Bottom|Left)Color` Border color, e.g. '9966CC' -- `gridSpan` Number of columns spanned -- `vMerge` *restart* or *continue* - ### Cell span You can span a cell on multiple columns by using `gridSpan` or multiple rows by using `vMerge`. @@ -749,17 +645,6 @@ $textrun = $section->addTextRun(); $textrun->addImage('http://php.net/logo.jpg'); ``` -### Image styles - -Available image styles: - -- `width` Width in pixels -- `height` Height in pixels -- `align` Image alignment, *left*, *right*, or *center* -- `marginTop` Top margin in inches, can be negative -- `marginLeft` Left margin in inches, can be negative -- `wrappingStyle` Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront* - ### Watermarks To add a watermark (or page background image), your section needs a header reference. After creating a header, you can use the `addWatermark` method to add a watermark. @@ -856,6 +741,127 @@ To be completed. To be completed. +# Styles + +## Section + +Below are the available styles for section: + +- `orientation` Page orientation, i.e. 'portrait' (default) or 'landscape' +- `marginTop` Page margin top in twips +- `marginLeft` Page margin left in twips +- `marginRight` Page margin right in twips +- `marginBottom` Page margin bottom in twips +- `borderTopSize` Border top size in twips +- `borderTopColor` Border top color +- `borderLeftSize` Border left size in twips +- `borderLeftColor` Border left color +- `borderRightSize` Border right size in twips +- `borderRightColor` Border right color +- `borderBottomSize` Border bottom size in twips +- `borderBottomColor` Border bottom color +- `headerHeight` Spacing to top of header +- `footerHeight` Spacing to bottom of footer +- `gutter` Page gutter spacing +- `colsNum` Number of columns +- `colsSpace` Spacing between columns +- `breakType` Section break type (nextPage, nextColumn, continuous, evenPage, oddPage) + +The following two styles are automatically set by the use of the `orientation` style. You can alter them but that's not recommended. + +- `pageSizeW` Page width in twips +- `pageSizeH` Page height in twips + +## Font + +Available font styles: + +- `name` Font name, e.g. *Arial* +- `size` Font size, e.g. *20*, *22*, +- `hint` Font content type, *default*, *eastAsia*, or *cs* +- `bold` Bold, *true* or *false* +- `italic` Italic, *true* or *false* +- `superScript` Superscript, *true* or *false* +- `subScript` Subscript, *true* or *false* +- `underline` Underline, *dash*, *dotted*, etc. +- `strikethrough` Strikethrough, *true* or *false* +- `doubleStrikethrough` Double strikethrough, *true* or *false* +- `color` Font color, e.g. *FF0000* +- `fgColor` Font highlight color, e.g. *yellow*, *green*, *blue* +- `bgColor` Font background color, e.g. *FF0000* +- `smallCaps` Small caps, *true* or *false* +- `allCaps` All caps, *true* or *false* + +## Paragraph + +Available paragraph styles: + +- `align` Paragraph alignment, *left*, *right* or *center* +- `spaceBefore` Space before paragraph +- `spaceAfter` Space after paragraph +- `indent` Indent by how much +- `hanging` Hanging by how much +- `basedOn` Parent style +- `next` Style for next paragraph +- `widowControl` Allow first/last line to display on a separate page, *true* or *false* +- `keepNext` Keep paragraph with next paragraph, *true* or *false* +- `keepLines` Keep all lines on one page, *true* or *false* +- `pageBreakBefore` Start paragraph on next page, *true* or *false* +- `lineHeight` text line height, e.g. *1.0*, *1.5*, ect... +- `tabs` Set of custom tab stops + +## Table + +Table styles: + +- `width` Table width in percent +- `bgColor` Background color, e.g. '9966CC' +- `border(Top|Right|Bottom|Left)Size` Border size in twips +- `border(Top|Right|Bottom|Left)Color` Border color, e.g. '9966CC' +- `cellMargin(Top|Right|Bottom|Left)` Cell margin in twips + +Row styles: + +- `tblHeader` Repeat table row on every new page, *true* or *false* +- `cantSplit` Table row cannot break across pages, *true* or *false* +- `exactHeight` Row height is exact or at least + +Cell styles: + +- `width` Cell width in twips +- `valign` Vertical alignment, *top*, *center*, *both*, *bottom* +- `textDirection` Direction of text +- `bgColor` Background color, e.g. '9966CC' +- `border(Top|Right|Bottom|Left)Size` Border size in twips +- `border(Top|Right|Bottom|Left)Color` Border color, e.g. '9966CC' +- `gridSpan` Number of columns spanned +- `vMerge` *restart* or *continue* + +## Image + +Available image styles: + +- `width` Width in pixels +- `height` Height in pixels +- `align` Image alignment, *left*, *right*, or *center* +- `marginTop` Top margin in inches, can be negative +- `marginLeft` Left margin in inches, can be negative +- `wrappingStyle` Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront* + +## Numbering level + +- `start` Starting value +- `format` Numbering format bullet|decimal|upperRoman|lowerRoman|upperLetter|lowerLetter +- `restart` Restart numbering level symbol +- `suffix` Content between numbering symbol and paragraph text tab|space|nothing +- `text` Numbering level text e.g. %1 for nonbullet or bullet character +- `align` Numbering symbol align left|center|right|both +- `left` See paragraph style +- `hanging` See paragraph style +- `tabPos` See paragraph style +- `font` Font name +- `hint` See font style + # Templates You can create a docx template with included search-patterns that can be replaced by any value you wish. Only single-line values can be replaced. To load a template file, use the `loadTemplate` method. After loading the docx template, you can use the `setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. It is not possible to add new PHPWord elements to a loaded template file. diff --git a/docs/styles.rst b/docs/styles.rst new file mode 100644 index 00000000..cd07a9f7 --- /dev/null +++ b/docs/styles.rst @@ -0,0 +1,137 @@ +.. _styles: + +Styles +====== + +Section +------- + +Below are the available styles for section: + +- ``orientation`` Page orientation, i.e. 'portrait' (default) or + 'landscape' +- ``marginTop`` Page margin top in twips +- ``marginLeft`` Page margin left in twips +- ``marginRight`` Page margin right in twips +- ``marginBottom`` Page margin bottom in twips +- ``borderTopSize`` Border top size in twips +- ``borderTopColor`` Border top color +- ``borderLeftSize`` Border left size in twips +- ``borderLeftColor`` Border left color +- ``borderRightSize`` Border right size in twips +- ``borderRightColor`` Border right color +- ``borderBottomSize`` Border bottom size in twips +- ``borderBottomColor`` Border bottom color +- ``headerHeight`` Spacing to top of header +- ``footerHeight`` Spacing to bottom of footer +- ``gutter`` Page gutter spacing +- ``colsNum`` Number of columns +- ``colsSpace`` Spacing between columns +- ``breakType`` Section break type (nextPage, nextColumn, continuous, + evenPage, oddPage) + +The following two styles are automatically set by the use of the +``orientation`` style. You can alter them but that's not recommended. + +- ``pageSizeW`` Page width in twips +- ``pageSizeH`` Page height in twips + +Font +---- + +Available font styles: + +- ``name`` Font name, e.g. *Arial* +- ``size`` Font size, e.g. *20*, *22*, +- ``hint`` Font content type, *default*, *eastAsia*, or *cs* +- ``bold`` Bold, *true* or *false* +- ``italic`` Italic, *true* or *false* +- ``superScript`` Superscript, *true* or *false* +- ``subScript`` Subscript, *true* or *false* +- ``underline`` Underline, *dash*, *dotted*, etc. +- ``strikethrough`` Strikethrough, *true* or *false* +- ``doubleStrikethrough`` Double strikethrough, *true* or *false* +- ``color`` Font color, e.g. *FF0000* +- ``fgColor`` Font highlight color, e.g. *yellow*, *green*, *blue* +- ``bgColor`` Font background color, e.g. *FF0000* +- ``smallCaps`` Small caps, *true* or *false* +- ``allCaps`` All caps, *true* or *false* + +Paragraph +--------- + +Available paragraph styles: + +- ``align`` Paragraph alignment, *left*, *right* or *center* +- ``spaceBefore`` Space before paragraph +- ``spaceAfter`` Space after paragraph +- ``indent`` Indent by how much +- ``hanging`` Hanging by how much +- ``basedOn`` Parent style +- ``next`` Style for next paragraph +- ``widowControl`` Allow first/last line to display on a separate page, + *true* or *false* +- ``keepNext`` Keep paragraph with next paragraph, *true* or *false* +- ``keepLines`` Keep all lines on one page, *true* or *false* +- ``pageBreakBefore`` Start paragraph on next page, *true* or *false* +- ``lineHeight`` text line height, e.g. *1.0*, *1.5*, ect... +- ``tabs`` Set of custom tab stops + +Table +----- + +Table styles: + +- ``width`` Table width in percent +- ``bgColor`` Background color, e.g. '9966CC' +- ``border(Top|Right|Bottom|Left)Size`` Border size in twips +- ``border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' +- ``cellMargin(Top|Right|Bottom|Left)`` Cell margin in twips + +Row styles: + +- ``tblHeader`` Repeat table row on every new page, *true* or *false* +- ``cantSplit`` Table row cannot break across pages, *true* or *false* +- ``exactHeight`` Row height is exact or at least + +Cell styles: + +- ``width`` Cell width in twips +- ``valign`` Vertical alignment, *top*, *center*, *both*, *bottom* +- ``textDirection`` Direction of text +- ``bgColor`` Background color, e.g. '9966CC' +- ``border(Top|Right|Bottom|Left)Size`` Border size in twips +- ``border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' +- ``gridSpan`` Number of columns spanned +- ``vMerge`` *restart* or *continue* + +Image +----- + +Available image styles: + +- ``width`` Width in pixels +- ``height`` Height in pixels +- ``align`` Image alignment, *left*, *right*, or *center* +- ``marginTop`` Top margin in inches, can be negative +- ``marginLeft`` Left margin in inches, can be negative +- ``wrappingStyle`` Wrapping style, *inline*, *square*, *tight*, + *behind*, or *infront* + +Numbering level +--------------- + +- ``start`` Starting value +- ``format`` Numbering format + bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter +- ``restart`` Restart numbering level symbol +- ``suffix`` Content between numbering symbol and paragraph text + tab\|space\|nothing +- ``text`` Numbering level text e.g. %1 for nonbullet or bullet + character +- ``align`` Numbering symbol align left\|center\|right\|both +- ``left`` See paragraph style +- ``hanging`` See paragraph style +- ``tabPos`` See paragraph style +- ``font`` Font name +- ``hint`` See font style From e952fdefb5730f59087f77404d4d7884128407c7 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 18:29:24 +0700 Subject: [PATCH 255/326] Refactor PhpWord to reduce dependencies --- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/PhpWord.php | 244 ++++++++-------------- src/PhpWord/Reader/ODText/Content.php | 2 +- 3 files changed, 85 insertions(+), 163 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 5093d3f4..4398ef16 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -25,7 +25,7 @@ namespace PhpOffice\PhpWord\Element; * @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null) * @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null) * @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null) - * @method ListItem addListItem(string $text, int $depth = 0, mixed $fStyle = null, mixed $listStyle = null, mixed $pStyle = null) + * @method ListItem addListItem(string $txt, int $depth = 0, mixed $font = null, mixed $list = null, mixed $para = null) * @method ListItemRun addListItemRun(int $depth = 0, mixed $listStyle = null, mixed $pStyle = null) * @method Footnote addFootnote(mixed $pStyle = null) * @method Endnote addEndnote(mixed $pStyle = null) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index e06080c1..9c8d5a90 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -17,14 +17,25 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Collection\Endnotes; -use PhpOffice\PhpWord\Collection\Footnotes; -use PhpOffice\PhpWord\Collection\Titles; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Exception\Exception; /** * PHPWord main class + * + * @method Collection\Titles getTitles() + * @method Collection\Footnotes getFootnotes() + * @method Collection\Endnotes getEndnotes() + * @method int addTitle(Element\Title $title) + * @method int addFootnote(Element\Footnote $footnote) + * @method int addEndnote(Element\Endnote $endnote) + * + * @method Style\Paragraph addParagraphStyle(string $styleName, array $styles) + * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null) + * @method Style\Font addLinkStyle(string $styleName, mixed $styles) + * @method Style\Font addTitleStyle(int $depth, mixed $fontStyle, mixed $paragraphStyle = null) + * @method Style\Table addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null) + * @method Style\Numbering addNumberingStyle(string $styleName, mixed $styles) */ class PhpWord { @@ -54,35 +65,84 @@ class PhpWord private $sections = array(); /** - * Collection of titles + * Collections * - * @var \PhpOffice\PhpWord\Collection\Titles + * @var array */ - private $titles; + private $collections = array(); /** - * Collection of footnotes + * Create new instance * - * @var \PhpOffice\PhpWord\Collection\Footnotes - */ - private $footnotes; - - /** - * Collection of endnotes - * - * @var \PhpOffice\PhpWord\Collection\Endnotes - */ - private $endnotes; - - /** - * Create new + * Collections are created dynamically */ public function __construct() { $this->documentProperties = new DocumentProperties(); - $this->titles = new Titles(); - $this->footnotes = new Footnotes(); - $this->endnotes = new Endnotes(); + + $collections = array('Titles', 'Footnotes', 'Endnotes'); + foreach ($collections as $collection) { + $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; + $this->collections[$collection] = new $class(); + } + } + + /** + * Dynamic function call to reduce static dependency + * + * Usage: + * - Getting and adding collections (Titles, Footnotes, and Endnotes) + * - Adding style + * + * @param mixed $function + * @param mixed $args + * @return mixed + * + * @since 0.12.0 + */ + public function __call($function, $args) + { + $function = strtolower($function); + + $getCollection = array(); + $addCollection = array(); + $addStyle = array(); + + $collections = array('Title', 'Footnote', 'Endnote'); + foreach ($collections as $collection) { + $getCollection[] = strtolower("get{$collection}s"); + $addCollection[] = strtolower("add{$collection}"); + } + + $styles = array('Paragraph', 'Font', 'Table', 'Numbering', 'Link', 'Title'); + foreach ($styles as $style) { + $addStyle[] = strtolower("add{$style}style"); + } + + // Run get collection method + if (in_array($function, $getCollection)) { + $key = ucfirst(str_replace('get', '', $function)); + + return $this->collections[$key]; + } + + // Run add collection item method + if (in_array($function, $addCollection)) { + $key = ucfirst(str_replace('add', '', $function) . 's'); + + /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collectionObject */ + $collectionObject = $this->collections[$key]; + + return $collectionObject->addItem($args[0]); + } + + // Run add style method + if (in_array($function, $addStyle)) { + return forward_static_call_array(array('PhpOffice\\PhpWord\\Style', $function), $args); + } + + // All other methods + return null; } /** @@ -133,69 +193,6 @@ class PhpWord return $section; } - /** - * Get titles - * - * @return \PhpOffice\PhpWord\Collection\Titles - */ - public function getTitles() - { - return $this->titles; - } - - /** - * Add new title - * - * @param \PhpOffice\PhpWord\Element\Title $title - * @return int - */ - public function addTitle($title) - { - return $this->titles->addItem($title); - } - - /** - * Get footnotes - * - * @return \PhpOffice\PhpWord\Collection\Footnotes - */ - public function getFootnotes() - { - return $this->footnotes; - } - - /** - * Add new footnote - * - * @param \PhpOffice\PhpWord\Element\Footnote $footnote - * @return int - */ - public function addFootnote($footnote) - { - return $this->footnotes->addItem($footnote); - } - - /** - * Get endnotes - * - * @return \PhpOffice\PhpWord\Collection\Endnotes - */ - public function getEndnotes() - { - return $this->endnotes; - } - - /** - * Add new endnote - * - * @param \PhpOffice\PhpWord\Element\Endnote $endnote - * @return int - */ - public function addEndnote($endnote) - { - return $this->endnotes->addItem($endnote); - } - /** * Get default font name * @@ -247,81 +244,6 @@ class PhpWord return Style::setDefaultParagraphStyle($styles); } - /** - * Adds a paragraph style definition to styles.xml - * - * @param string $styleName - * @param array $styles - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function addParagraphStyle($styleName, $styles) - { - return Style::addParagraphStyle($styleName, $styles); - } - - /** - * Adds a font style definition to styles.xml - * - * @param string $styleName - * @param mixed $fontStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font - */ - public function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) - { - return Style::addFontStyle($styleName, $fontStyle, $paragraphStyle); - } - - /** - * Adds a table style definition to styles.xml - * - * @param string $styleName - * @param mixed $styleTable - * @param mixed $styleFirstRow - * @return \PhpOffice\PhpWord\Style\Table - */ - public function addTableStyle($styleName, $styleTable, $styleFirstRow = null) - { - return Style::addTableStyle($styleName, $styleTable, $styleFirstRow); - } - - /** - * Adds a numbering style - * - * @param string $styleName - * @param mixed $styles - * @return \PhpOffice\PhpWord\Style\Numbering - */ - public function addNumberingStyle($styleName, $styles) - { - return Style::addNumberingStyle($styleName, $styles); - } - - /** - * Adds a hyperlink style to styles.xml - * - * @param string $styleName - * @param mixed $styles - * @return \PhpOffice\PhpWord\Style\Font - */ - public function addLinkStyle($styleName, $styles) - { - return Style::addLinkStyle($styleName, $styles); - } - - /** - * Adds a heading style definition to styles.xml - * - * @param int $depth - * @param mixed $fontStyle - * @param mixed $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font - */ - public function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) - { - return Style::addTitleStyle($depth, $fontStyle, $paragraphStyle); - } - /** * Load template by filename * diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 12b39f74..034789ff 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -57,7 +57,7 @@ class Content extends AbstractPart $listItems = $xmlReader->getElements('text:list-item/text:p', $node); foreach ($listItems as $listItem) { // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem); - $section->addListItem($listItem->nodeValue); + $section->addListItem($listItem->nodeValue, 0); } break; } From 6839ee41dd0d0fe0d7d3286592c24e2e8446db18 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 20:11:44 +0700 Subject: [PATCH 256/326] New `PhpWord::save()` method to encapsulate `IOFactory` --- CHANGELOG.md | 1 + README.md | 13 ++++------ docs/general.rst | 13 ++++------ docs/src/documentation.md | 13 ++++------ samples/Sample_Header.php | 12 ++++------ src/PhpWord/PhpWord.php | 37 +++++++++++++++++++++++++++++ tests/PhpWord/Tests/PhpWordTest.php | 12 ++++++++++ 7 files changed, 67 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d99348..7d4010ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme - Paragraph: Added shading to the paragraph style for full width shading - @lrobert GH-264 - RTF Writer: Support for sections, margins, and borders - @ivanlanin GH-249 - Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin GH-249 +- General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin ### Bugfixes diff --git a/README.md b/README.md index fefde4eb..a9006f2c 100644 --- a/README.md +++ b/README.md @@ -100,15 +100,10 @@ $fontStyle->setSize(22); $myTextElement = $section->addText('Hello World!'); $myTextElement->setFontStyle($fontStyle); -// Finally, write the document: -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); -$objWriter->save('helloWorld.docx'); - -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); -$objWriter->save('helloWorld.odt'); - -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); -$objWriter->save('helloWorld.rtf'); +// Finally, save the document: +$phpWord->save('helloWorld.docx'); +$phpWord->save('helloWorld.odt', 'ODText'); +$phpWord->save('helloWorld.rtf', 'RTF'); ``` ## Known issues diff --git a/docs/general.rst b/docs/general.rst index 270608f7..0bbeb2ec 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -43,15 +43,10 @@ folder `__. $myTextElement = $section->addText('Hello World!'); $myTextElement->setFontStyle($fontStyle); - // Finally, write the document: - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); - $objWriter->save('helloWorld.docx'); - - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); - $objWriter->save('helloWorld.odt'); - - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); - $objWriter->save('helloWorld.rtf'); + // Finally, save the document: + $phpWord->save('helloWorld.docx'); + $phpWord->save('helloWorld.odt', 'ODText'); + $phpWord->save('helloWorld.rtf', 'RTF'); Settings -------- diff --git a/docs/src/documentation.md b/docs/src/documentation.md index c76ec1f2..c2fc5e77 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -238,15 +238,10 @@ $fontStyle->setSize(22); $myTextElement = $section->addText('Hello World!'); $myTextElement->setFontStyle($fontStyle); -// Finally, write the document: -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); -$objWriter->save('helloWorld.docx'); - -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); -$objWriter->save('helloWorld.odt'); - -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); -$objWriter->save('helloWorld.rtf'); +// Finally, save the document: +$phpWord->save('helloWorld.docx'); +$phpWord->save('helloWorld.odt', 'ODText'); +$phpWord->save('helloWorld.rtf', 'RTF'); ``` ## Settings diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 7af23c94..d915c039 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -4,7 +4,6 @@ */ use PhpOffice\PhpWord\Autoloader; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\IOFactory; error_reporting(E_ALL); define('CLI', (PHP_SAPI == 'cli') ? true : false); @@ -59,12 +58,11 @@ function write($phpWord, $filename, $writers) $result = ''; // Write documents - foreach ($writers as $writer => $extension) { - $result .= date('H:i:s') . " Write to {$writer} format"; - if (!is_null($extension)) { - $xmlWriter = IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save(__DIR__ . "/{$filename}.{$extension}"); - rename(__DIR__ . "/{$filename}.{$extension}", __DIR__ . "/results/{$filename}.{$extension}"); + foreach ($writers as $format => $extension) { + $result .= date('H:i:s') . " Write to {$format} format"; + if ($extension !== null) { + $targetFile = __DIR__ . "/results/{$filename}.{$extension}"; + $phpWord->save($targetFile, $format); } else { $result .= ' ... NOT DONE!'; } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 9c8d5a90..8e889cce 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -260,6 +260,43 @@ class PhpWord } } + /** + * Save to file or download + * + * All exceptions should already been handled by the writers + * + * @param string $filename + * @param string $format + * @param bool $download + * @return bool + */ + public function save($filename, $format = 'Word2007', $download = false) + { + $mime = array( + 'Word2007' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'ODT' => 'application/vnd.oasis.opendocument.text', + 'RTF' => 'application/rtf', + 'HTML' => 'text/html', + 'PDF' => 'application/pdf', + ); + + $writer = IOFactory::createWriter($this, $format); + + if ($download === true) { + header("Content-Description: File Transfer"); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + header('Content-Type: ' . $mime[$format]); + header('Content-Transfer-Encoding: binary'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Expires: 0'); + $filename = 'php://output'; // Change filename to force download + } + + $writer->save($filename); + + return true; + } + /** * Create new section * diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 6a9e6b26..ca49bf28 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -158,4 +158,16 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->loadTemplate($templateFqfn); } + + /** + * Test save + */ + public function testSave() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Hello world!'); + + $this->assertTrue($phpWord->save('test.docx', 'Word2007', true)); + } } From 1ec0589c557406725bf03eb0f791b6f8002a06a3 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 8 Jun 2014 22:38:50 +0700 Subject: [PATCH 257/326] Update basic example --- README.md | 18 ++++++++++++------ docs/general.rst | 9 +++++---- docs/src/documentation.md | 9 +++++---- src/PhpWord/PhpWord.php | 1 + 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a9006f2c..97e5b642 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,14 @@ require_once 'path/to/PhpWord/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); ``` -## Usages +## Getting started -The following is a basic example of the PHPWord library. More examples are provided in the [samples folder](samples/). +The following is a basic usage example of the PHPWord library. ```php +require_once 'src/PhpWord/Autoloader.php'; +\PhpOffice\PhpWord\Autoloader::register(); + $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Every element you want to append to the word document is placed in a section. @@ -93,10 +96,11 @@ $section->addText('Hello world! I am formatted by a user defined style', 'myOwnStyle'); // You can also put the appended element to local object like this: -$fontStyle = new \PhpOffice\PhpWord\Style\Font(); -$fontStyle->setBold(true); -$fontStyle->setName('Verdana'); -$fontStyle->setSize(22); +$fontStyle = array( + 'name' => 'Verdana', + 'size' => 22, + 'bold' => true, +); $myTextElement = $section->addText('Hello World!'); $myTextElement->setFontStyle($fontStyle); @@ -106,6 +110,8 @@ $phpWord->save('helloWorld.odt', 'ODText'); $phpWord->save('helloWorld.rtf', 'RTF'); ``` +More examples are provided in the [samples folder](samples/). You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/) for more detail. + ## Known issues - GH-238: PHPWord uses temporary folder with `sys_get_temp_dir()` extensively. The default setting on some systems (especially Windows) do not give appropriate read/write permission to this folder. Run `samples/index.php` either by CLI or by web browsers to check if you have this requirement fulfilled. diff --git a/docs/general.rst b/docs/general.rst index 0bbeb2ec..60d9b609 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -36,10 +36,11 @@ folder `__. 'myOwnStyle'); // You can also put the appended element to local object like this: - $fontStyle = new \PhpOffice\PhpWord\Style\Font(); - $fontStyle->setBold(true); - $fontStyle->setName('Verdana'); - $fontStyle->setSize(22); + $fontStyle = array( + 'name' => 'Verdana', + 'size' => 22, + 'bold' => true, + ); $myTextElement = $section->addText('Hello World!'); $myTextElement->setFontStyle($fontStyle); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index c2fc5e77..144222c1 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -231,10 +231,11 @@ $section->addText('Hello world! I am formatted by a user defined style', 'myOwnStyle'); // You can also put the appended element to local object like this: -$fontStyle = new \PhpOffice\PhpWord\Style\Font(); -$fontStyle->setBold(true); -$fontStyle->setName('Verdana'); -$fontStyle->setSize(22); +$fontStyle = array( + 'name' => 'Verdana', + 'size' => 22, + 'bold' => true, +); $myTextElement = $section->addText('Hello World!'); $myTextElement->setFontStyle($fontStyle); diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 8e889cce..c8ed568c 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -280,6 +280,7 @@ class PhpWord 'PDF' => 'application/pdf', ); + /** @var \PhpOffice\PhpWord\Writer\WriterInterface $writer */ $writer = IOFactory::createWriter($this, $format); if ($download === true) { From 4c04071fd519a21d2234dcbee1ee195483ab2973 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 9 Jun 2014 18:52:06 +0700 Subject: [PATCH 258/326] Fix typo: ODT > ODText --- src/PhpWord/PhpWord.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index c8ed568c..de9d8433 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -274,7 +274,7 @@ class PhpWord { $mime = array( 'Word2007' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'ODT' => 'application/vnd.oasis.opendocument.text', + 'ODText' => 'application/vnd.oasis.opendocument.text', 'RTF' => 'application/rtf', 'HTML' => 'text/html', 'PDF' => 'application/pdf', From d17a806305010b97b03441739cde7913645a745f Mon Sep 17 00:00:00 2001 From: Brandon Skrtich Date: Mon, 9 Jun 2014 15:17:40 -0600 Subject: [PATCH 259/326] Small fixes for addHtml. Adding some HTML Entities to the test for addHTML --- src/PhpWord/Shared/Html.php | 9 +++++++-- tests/PhpWord/Tests/Shared/HtmlTest.php | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 8abfea2f..fc23b5b0 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -42,9 +42,14 @@ class Html * which could be applied when such an element occurs in the parseNode function. */ - // Preprocess: remove all line ends, decode HTML entity, and add body tag for HTML fragments + // Preprocess: remove all line ends, decode HTML entity, + // fix ampersand and angle brackets and add body tag for HTML fragments $html = str_replace(array("\n", "\r"), '', $html); - $html = html_entity_decode($html); + $html = str_replace(array('<', '>', '&'), array('_lt_', '_gt_', '_amp_'), $html); + $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8'); + $html = str_replace('&', '&', $html); + $html = str_replace(array('_lt_', '_gt_', '_amp_'), array('<', '>', '&'), $html); + if ($fullHTML === false) { $html = '' . $html . ''; } diff --git a/tests/PhpWord/Tests/Shared/HtmlTest.php b/tests/PhpWord/Tests/Shared/HtmlTest.php index 730600d7..e7b3533e 100644 --- a/tests/PhpWord/Tests/Shared/HtmlTest.php +++ b/tests/PhpWord/Tests/Shared/HtmlTest.php @@ -60,6 +60,12 @@ class HtmlTest extends \PHPUnit_Framework_TestCase $content .= '
    HeaderContent
    '; $content .= '

    • Bullet
      • Bullet
    '; $content .= '
    1. Bullet
    '; + $content .= "'Single Quoted Text'"; + $content .= '"Double Quoted Text"'; + $content .= '& Ampersand'; + $content .= '<>“‘’«»‹›'; + $content .= '&•°…™©®—'; + $content .= '–   ²³¼½¾'; Html::addHtml($section, $content); } } From 8e93c91bb00c892347dc0f63b741eb5347d4e71b Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 11 Jun 2014 00:57:52 +0700 Subject: [PATCH 260/326] Update changelog for #270 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4010ec..9b741e57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme ### Bugfixes - Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo GH-261 +- `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich GH-270 ### Deprecated From 056ff5e676fcac97f48354ee2075a991de442fe1 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 10 Jun 2014 07:11:32 +0700 Subject: [PATCH 261/326] Basic chart support --- samples/Sample_32_Chart.php | 26 ++ src/PhpWord/Collection/Charts.php | 27 ++ src/PhpWord/Element/AbstractContainer.php | 4 +- src/PhpWord/Element/AbstractElement.php | 2 +- src/PhpWord/Element/Chart.php | 129 +++++++ src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/PhpWord.php | 6 +- src/PhpWord/Shared/XMLWriter.php | 23 ++ src/PhpWord/Writer/Word2007.php | 36 ++ src/PhpWord/Writer/Word2007/Element/Chart.php | 79 +++++ src/PhpWord/Writer/Word2007/Part/Chart.php | 331 ++++++++++++++++++ .../Writer/Word2007/Part/ContentTypes.php | 7 +- .../Tests/Writer/Word2007/ElementTest.php | 2 +- 14 files changed, 668 insertions(+), 8 deletions(-) create mode 100644 samples/Sample_32_Chart.php create mode 100644 src/PhpWord/Collection/Charts.php create mode 100644 src/PhpWord/Element/Chart.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Chart.php create mode 100644 src/PhpWord/Writer/Word2007/Part/Chart.php diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php new file mode 100644 index 00000000..52c19f3c --- /dev/null +++ b/samples/Sample_32_Chart.php @@ -0,0 +1,26 @@ +addSection(array('colsNum' => 2)); +$phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240)); + +$charts = array('pie', 'doughnut', 'line', 'area', 'scatter', 'bar', 'radar'); +$labels = array('A', 'B', 'C', 'D', 'E'); +$data = array(1, 3, 2, 5, 4); + +foreach ($charts as $chart) { + $section->addTitle(ucfirst($chart), 1); + $section->addChart($chart, $labels, $data); + $section->addTextBreak(); +} + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php new file mode 100644 index 00000000..cfccee2e --- /dev/null +++ b/src/PhpWord/Collection/Charts.php @@ -0,0 +1,27 @@ + array('Section'), 'TOC' => array('Section'), 'PageBreak' => array('Section'), + 'Chart' => array('Section'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index fe133fdd..3fd2e4d0 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -109,7 +109,7 @@ abstract class AbstractElement protected $mediaRelation = false; /** - * Is part of collection; true for Title, Footnote, and Endnote + * Is part of collection; true for Title, Footnote, Endnote, and Chart * * @var bool */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php new file mode 100644 index 00000000..46b7b784 --- /dev/null +++ b/src/PhpWord/Element/Chart.php @@ -0,0 +1,129 @@ +setType($type); + $this->setLabels($labels); + $this->setData($data); + } + + /** + * Get type + * + * @return array + */ + public function getType() + { + return $this->type; + } + + /** + * Set type + * + * @param array $value + */ + public function setType($value) + { + $enum = array('pie', 'doughnut', 'line', 'bar', 'area', 'radar', 'scatter'); + $this->type = $this->setEnumVal($value, $enum, 'pie'); + } + + /** + * Get labels + * + * @return array + */ + public function getLabels() + { + return $this->labels; + } + + /** + * Set labels + * + * @param array $value + */ + public function setLabels($value) + { + $this->labels = $value; + } + + /** + * Get data + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * Set data + * + * @param array $value + */ + public function setData($value) + { + $this->data = $value; + } +} diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index e263933c..162a703e 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -37,7 +37,7 @@ class Footnote extends AbstractContainer protected $paragraphStyle; /** - * Is part of collection; true for Title, Footnote, and Endnote + * Is part of collection * * @var bool */ diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index a4faeb70..8d385845 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -47,7 +47,7 @@ class Title extends AbstractElement private $style; /** - * Is part of collection; true for Title, Footnote, and Endnote + * Is part of collection * * @var bool */ diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index de9d8433..d4c8df9c 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -26,9 +26,11 @@ use PhpOffice\PhpWord\Exception\Exception; * @method Collection\Titles getTitles() * @method Collection\Footnotes getFootnotes() * @method Collection\Endnotes getEndnotes() + * @method Collection\Charts getCharts() * @method int addTitle(Element\Title $title) * @method int addFootnote(Element\Footnote $footnote) * @method int addEndnote(Element\Endnote $endnote) + * @method int addChart(Element\Chart $chart) * * @method Style\Paragraph addParagraphStyle(string $styleName, array $styles) * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null) @@ -80,7 +82,7 @@ class PhpWord { $this->documentProperties = new DocumentProperties(); - $collections = array('Titles', 'Footnotes', 'Endnotes'); + $collections = array('Titles', 'Footnotes', 'Endnotes', 'Charts'); foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); @@ -108,7 +110,7 @@ class PhpWord $addCollection = array(); $addStyle = array(); - $collections = array('Title', 'Footnote', 'Endnote'); + $collections = array('Title', 'Footnote', 'Endnote', 'Chart'); foreach ($collections as $collection) { $getCollection[] = strtolower("get{$collection}s"); $addCollection[] = strtolower("add{$collection}"); diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index cb00c70b..b2057bb9 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -139,6 +139,29 @@ class XMLWriter } } + /** + * Write simple element and attribute(s) block + * + * There are two options: + * 1. If the `$attributes` is an array, then it's an associative array of attributes + * 2. If not, then it's a simple attribute-value pair + * + * @param string $element + * @param string|array $attributes + * @param string $value + */ + public function writeBlock($element, $attributes, $value = null) + { + $this->xmlWriter->startElement($element); + if (!is_array($attributes)) { + $attributes = array($attributes => $value); + } + foreach ($attributes as $attribute => $value) { + $this->xmlWriter->writeAttribute($attribute, $value); + } + $this->xmlWriter->endElement(); + } + /** * Write element if ... * diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 751b58b6..d15f40ac 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -71,6 +71,7 @@ class Word2007 extends AbstractWriter implements WriterInterface 'Footer' => '', 'Footnotes' => '', 'Endnotes' => '', + 'Chart' => '', ); foreach (array_keys($this->parts) as $partName) { $partClass = get_class($this) . '\\Part\\' . $partName; @@ -127,6 +128,7 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->addNotes($zip, $rId, 'footnote'); $this->addNotes($zip, $rId, 'endnote'); + $this->addChart($zip, $rId); // Write parts foreach ($this->parts as $partName => $fileName) { @@ -249,6 +251,40 @@ class Word2007 extends AbstractWriter implements WriterInterface } } + /** + * Add chart + * + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip + * @param integer $rId + */ + private function addChart(ZipArchive $zip, &$rId) + { + $phpWord = $this->getPhpWord(); + + $collection = $phpWord->getCharts(); + $index = 0; + if ($collection->countItems() > 0) { + foreach ($collection->getItems() as $chart) { + $index++; + $rId++; + $filename = "charts/chart{$index}.xml"; + + // ContentTypes.xml + $this->contentTypes['override']["/word/{$filename}"] = 'chart'; + + // word/_rels/document.xml.rel + $this->relationships[] = array('target' => $filename, 'type' => 'chart', 'rID' => $rId); + + // word/charts/chartN.xml + /** @var \PhpOffice\PhpWord\Element\Chart $chart */ + $chart->setRelationId($rId); + $writerPart = $this->getWriterPart('Chart'); + $writerPart->setElement($chart); + $zip->addFromString("word/{$filename}", $writerPart->write()); + } + } + } + /** * Register content types for each media * diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php new file mode 100644 index 00000000..3c4e43f2 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -0,0 +1,79 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof ChartElement) { + return; + } + + if (!$this->withoutP) { + $xmlWriter->startElement('w:p'); + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:drawing'); + $xmlWriter->startElement('wp:inline'); + + // EMU + $xmlWriter->startElement('wp:extent'); + $xmlWriter->writeAttribute('cx', '2000000'); + $xmlWriter->writeAttribute('cy', '2000000'); + $xmlWriter->endElement(); // wp:extent + + $xmlWriter->startElement('wp:docPr'); + $xmlWriter->writeAttribute('id', $element->getRelationId()); + $xmlWriter->writeAttribute('name', 'Chart'. $element->getRelationId()); + $xmlWriter->endElement(); // wp:docPr + + $xmlWriter->startElement('a:graphic'); + $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); + $xmlWriter->startElement('a:graphicData'); + $xmlWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); + + $xmlWriter->startElement('c:chart'); + $xmlWriter->writeAttribute('r:id', 'rId' . $element->getRelationId()); + $xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->endElement(); // c:chart + + $xmlWriter->endElement(); // a:graphicData + $xmlWriter->endElement(); // a:graphic + + $xmlWriter->endElement(); // wp:inline + $xmlWriter->endElement(); // w:drawing + $xmlWriter->endElement(); // w:r + + $this->endElementP(); // w:p + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php new file mode 100644 index 00000000..13525fe7 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -0,0 +1,331 @@ +element = $element; + } + + /** + * Write part + * + * @return string + */ + public function write() + { + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('c:chartSpace'); + $xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); + $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + + $xmlWriter->writeBlock('c:roundedCorners', 'val', '0'); + + $xmlWriter->startElement('c:chart'); + $this->writePlotArea($xmlWriter); + $xmlWriter->endElement(); // c:chart + + $xmlWriter->endElement(); // c:chartSpace + + return $xmlWriter->getData(); + } + + /** + * Write plot area + */ + private function writePlotArea(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:plotArea'); + + $method = "write{$this->element->getType()}Chart"; + $this->$method($xmlWriter); + + $xmlWriter->endElement(); // c:plotArea + } + + /** + * Write pie chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html + */ + private function writePieChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:pieChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '1'); + + $this->writeSeries($xmlWriter); + + $xmlWriter->endElement(); // c:pie3DChart + } + + /** + * Write doughnut chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html + */ + private function writeDoughnutChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:doughnutChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '1'); + $xmlWriter->writeBlock('c:holeSize', 'val', '75'); + + $this->writeSeries($xmlWriter); + + $xmlWriter->endElement(); // c:doughnutChart + } + + /** + * Write bar chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html + */ + private function writeBarChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:barChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '0'); + $xmlWriter->writeBlock('c:barDir', 'val', 'col'); // bar|col + $xmlWriter->writeBlock('c:axId', 'val', '1'); + $xmlWriter->writeBlock('c:axId', 'val', '2'); + + $this->writeSeries($xmlWriter); + + $xmlWriter->endElement(); // c:barChart + + // Axes + $this->writeAxis($xmlWriter, 'cat'); + $this->writeAxis($xmlWriter, 'val'); + } + + /** + * Write line chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html + */ + private function writeLineChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:lineChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '0'); + $xmlWriter->writeBlock('c:axId', 'val', '1'); + $xmlWriter->writeBlock('c:axId', 'val', '2'); + + $this->writeSeries($xmlWriter); + + $xmlWriter->endElement(); // c:lineChart + + // Axes + $this->writeAxis($xmlWriter, 'cat'); + $this->writeAxis($xmlWriter, 'val'); + } + + /** + * Write area chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html + */ + private function writeAreaChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:areaChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '0'); + $xmlWriter->writeBlock('c:axId', 'val', '1'); + $xmlWriter->writeBlock('c:axId', 'val', '2'); + + $this->writeSeries($xmlWriter); + + $xmlWriter->endElement(); // c:areaChart + + // Axes + $this->writeAxis($xmlWriter, 'cat'); + $this->writeAxis($xmlWriter, 'val'); + } + + /** + * Write radar chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html + */ + private function writeRadarChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:radarChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '0'); + $xmlWriter->writeBlock('c:radarStyle', 'val', 'standard'); + $xmlWriter->writeBlock('c:axId', 'val', '1'); + $xmlWriter->writeBlock('c:axId', 'val', '2'); + + $this->writeSeries($xmlWriter); + + $xmlWriter->endElement(); // c:radarChart + + // Axes + $this->writeAxis($xmlWriter, 'cat'); + $this->writeAxis($xmlWriter, 'val'); + } + + /** + * Write scatter chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html + */ + private function writeScatterChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:scatterChart'); + + $xmlWriter->writeBlock('c:varyColors', 'val', '0'); + $xmlWriter->writeBlock('c:scatterStyle', 'val', 'lineMarker'); + $xmlWriter->writeBlock('c:axId', 'val', '1'); + $xmlWriter->writeBlock('c:axId', 'val', '2'); + + $this->writeSeries($xmlWriter, true); + + $xmlWriter->endElement(); // c:scatterChart + + // Axes + $this->writeAxis($xmlWriter, 'cat'); + $this->writeAxis($xmlWriter, 'val'); + } + + /** + * Write series + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param bool $scatter + */ + private function writeSeries(XMLWriter $xmlWriter, $scatter = false) + { + $xmlWriter->startElement('c:ser'); + + $xmlWriter->writeBlock('c:idx', 'val', '0'); + $xmlWriter->writeBlock('c:order', 'val', '0'); + + if ($scatter === true) { + $this->writeSeriesItems($xmlWriter, 'xVal', $this->element->getLabels()); + $this->writeSeriesItems($xmlWriter, 'yVal', $this->element->getData()); + } else { + $this->writeSeriesItems($xmlWriter, 'cat', $this->element->getLabels()); + $this->writeSeriesItems($xmlWriter, 'val', $this->element->getData()); + } + + $xmlWriter->endElement(); // c:ser + } + + /** + * Write series items + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $type + * @param array $values + */ + private function writeSeriesItems(XMLWriter $xmlWriter, $type, $values) + { + $types = array( + 'cat' => array('c:cat', 'c:strRef', 'c:strCache'), + 'val' => array('c:val', 'c:numRef', 'c:numCache'), + 'xVal' => array('c:xVal', 'c:strRef', 'c:strCache'), + 'yVal' => array('c:yVal', 'c:numRef', 'c:numCache'), + ); + list($itemType, $itemRef, $itemCache) = $types[$type]; + + $xmlWriter->startElement($itemType); + $xmlWriter->startElement($itemRef); + $xmlWriter->startElement($itemCache); + + $index = 0; + foreach ($values as $value) { + $xmlWriter->startElement('c:pt'); + $xmlWriter->writeAttribute('idx', $index); + + $xmlWriter->startElement('c:v'); + $xmlWriter->writeRaw($value); + $xmlWriter->endElement(); // c:v + + $xmlWriter->endElement(); // c:pt + $index++; + } + + $xmlWriter->endElement(); // $itemCache + + $xmlWriter->endElement(); // $itemRef + $xmlWriter->endElement(); // $itemType + } + + /** + * Write axis + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $type + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html + */ + private function writeAxis(XMLWriter $xmlWriter, $type) + { + $types = array( + 'cat' => array('c:catAx', '1', 'b', '2'), + 'val' => array('c:valAx', '2', 'l', '1'), + ); + list($axisType, $axisId, $axisPos, $axisCross) = $types[$type]; + + $xmlWriter->startElement($axisType); + + $xmlWriter->writeBlock('c:axId', 'val', $axisId); + $xmlWriter->writeBlock('c:axPos', 'val', $axisPos); + $xmlWriter->writeBlock('c:crossAx', 'val', $axisCross); + + $xmlWriter->startElement('c:scaling'); + $xmlWriter->writeBlock('c:orientation', 'val', 'minMax'); + $xmlWriter->endElement(); // c:scaling + + $xmlWriter->startElement('c:spPr'); + $xmlWriter->writeElement('a:noFill'); + $xmlWriter->startElement('a:ln'); + $xmlWriter->startElement('a:solidFill'); + $xmlWriter->writeBlock('a:srgbClr', 'val', '0FB7'); + $xmlWriter->endElement(); // a:solidFill + $xmlWriter->endElement(); // a:ln + $xmlWriter->endElement(); // c:crossAx + + $xmlWriter->endElement(); // $type + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index b6f23f47..ac636d3a 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -37,6 +37,7 @@ class ContentTypes extends AbstractPart $openXMLPrefix = 'application/vnd.openxmlformats-'; $wordMLPrefix = $openXMLPrefix . 'officedocument.wordprocessingml.'; + $drawingMLPrefix = $openXMLPrefix . 'officedocument.drawingml.'; $overrides = array( '/docProps/core.xml' => $openXMLPrefix . 'package.core-properties+xml', '/docProps/app.xml' => $openXMLPrefix . 'officedocument.extended-properties+xml', @@ -53,7 +54,11 @@ class ContentTypes extends AbstractPart $defaults = $contentTypes['default']; if (!empty($contentTypes['override'])) { foreach ($contentTypes['override'] as $key => $val) { - $overrides[$key] = $wordMLPrefix . $val . '+xml'; + if ($val == 'chart') { + $overrides[$key] = $drawingMLPrefix . $val . '+xml'; + } else { + $overrides[$key] = $wordMLPrefix . $val . '+xml'; + } } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index c774e9f3..2e76df12 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -41,7 +41,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', - 'Field', 'Line', 'Shape' + 'Field', 'Line', 'Shape', 'Chart' ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; From a93b686ca3826cf83dcec6a46a5dac2a10c9be4e Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 11 Jun 2014 23:04:13 +0700 Subject: [PATCH 262/326] Chart improvements --- src/PhpWord/Element/Chart.php | 4 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 15 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 315 ++++++++---------- 3 files changed, 152 insertions(+), 182 deletions(-) diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 46b7b784..5a93b827 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -69,7 +69,7 @@ class Chart extends AbstractElement /** * Get type * - * @return array + * @return string */ public function getType() { @@ -79,7 +79,7 @@ class Chart extends AbstractElement /** * Set type * - * @param array $value + * @param string $value */ public function setType($value) { diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 3c4e43f2..454ebce5 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -37,6 +37,8 @@ class Chart extends AbstractElement return; } + $rId = $element->getRelationId(); + if (!$this->withoutP) { $xmlWriter->startElement('w:p'); } @@ -46,15 +48,8 @@ class Chart extends AbstractElement $xmlWriter->startElement('wp:inline'); // EMU - $xmlWriter->startElement('wp:extent'); - $xmlWriter->writeAttribute('cx', '2000000'); - $xmlWriter->writeAttribute('cy', '2000000'); - $xmlWriter->endElement(); // wp:extent - - $xmlWriter->startElement('wp:docPr'); - $xmlWriter->writeAttribute('id', $element->getRelationId()); - $xmlWriter->writeAttribute('name', 'Chart'. $element->getRelationId()); - $xmlWriter->endElement(); // wp:docPr + $xmlWriter->writeBlock('wp:extent', array('cx' => '2000000', 'cy' => '2000000')); + $xmlWriter->writeBlock('wp:docPr', array('id' => $rId, 'name' => "Chart{$rId}")); $xmlWriter->startElement('a:graphic'); $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); @@ -62,7 +57,7 @@ class Chart extends AbstractElement $xmlWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); $xmlWriter->startElement('c:chart'); - $xmlWriter->writeAttribute('r:id', 'rId' . $element->getRelationId()); + $xmlWriter->writeAttribute('r:id', "rId{$rId}"); $xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $xmlWriter->endElement(); // c:chart diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 13525fe7..8d922013 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -24,6 +24,7 @@ use PhpOffice\PhpWord\Element\Chart as ChartElement; * Word2007 chart part writer: word/charts/chartx.xml * * @since 0.12.0 + * @link http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class Chart extends AbstractPart @@ -35,6 +36,18 @@ class Chart extends AbstractPart */ private $element; + private $types = array( + 'pie' => array('type' => 'pieChart', 'colors' => 1), + 'doughnut' => array('type' => 'doughnutChart', 'colors' => 1, 'hole' => 75), + 'bar' => array('type' => 'barChart', 'colors' => 0, 'axes' => true, 'bar' => 'col'), + 'line' => array('type' => 'lineChart', 'colors' => 0, 'axes' => true), + 'area' => array('type' => 'areaChart', 'colors' => 0, 'axes' => true), + 'radar' => array('type' => 'radarChart', 'colors' => 0, 'axes' => true, 'radar' => 'standard'), + 'scatter' => array('type' => 'scatterChart', 'colors' => 0, 'axes' => true, 'scatter' => 'marker'), + ); + + private $options = array(); + /** * Set chart element */ @@ -58,176 +71,92 @@ class Chart extends AbstractPart $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeBlock('c:roundedCorners', 'val', '0'); + $xmlWriter->writeBlock('c:date1904', 'val', 1); + $xmlWriter->writeBlock('c:lang', 'val', 'en-US'); + $xmlWriter->writeBlock('c:roundedCorners', 'val', 0); + + $this->writeChart($xmlWriter); + $this->writeShape($xmlWriter); - $xmlWriter->startElement('c:chart'); - $this->writePlotArea($xmlWriter); - $xmlWriter->endElement(); // c:chart $xmlWriter->endElement(); // c:chartSpace return $xmlWriter->getData(); } + /** + * Write chart + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html + */ + private function writeChart(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:chart'); + + $xmlWriter->writeBlock('c:autoTitleDeleted', 'val', 1); + $xmlWriter->writeBlock('c:dispBlanksAs', 'val', 'zero'); + + $this->writePlotArea($xmlWriter); + // $this->writeLegend($xmlWriter); + + $xmlWriter->endElement(); // c:chart + } + /** * Write plot area + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PlotArea.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html */ private function writePlotArea(XMLWriter $xmlWriter) { - $xmlWriter->startElement('c:plotArea'); + $type = $this->element->getType(); + $this->options = $this->types[$type]; - $method = "write{$this->element->getType()}Chart"; - $this->$method($xmlWriter); + $xmlWriter->startElement('c:plotArea'); + $xmlWriter->writeElement('c:layout'); + + // Chart + $xmlWriter->startElement('c:' . $this->options['type']); + + $xmlWriter->writeBlock('c:varyColors', 'val', $this->options['colors']); + if (isset($this->options['hole'])) { + $xmlWriter->writeBlock('c:holeSize', 'val', $this->options['hole']); + } + if (isset($this->options['bar'])) { + $xmlWriter->writeBlock('c:barDir', 'val', $this->options['bar']); // bar|col + } + if (isset($this->options['radar'])) { + $xmlWriter->writeBlock('c:radarStyle', 'val', $this->options['radar']); + } + if (isset($this->options['scatter'])) { + $xmlWriter->writeBlock('c:scatterStyle', 'val', $this->options['scatter']); + } + if (isset($this->options['axes'])) { + $xmlWriter->writeBlock('c:axId', 'val', 1); + $xmlWriter->writeBlock('c:axId', 'val', 2); + } + + // Series + $this->writeSeries($xmlWriter, isset($this->options['scatter'])); + + $xmlWriter->endElement(); // chart type + + // Axes + if (isset($this->options['axes'])) { + $this->writeAxis($xmlWriter, 'cat'); + $this->writeAxis($xmlWriter, 'val'); + } $xmlWriter->endElement(); // c:plotArea } - /** - * Write pie chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html - */ - private function writePieChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:pieChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '1'); - - $this->writeSeries($xmlWriter); - - $xmlWriter->endElement(); // c:pie3DChart - } - - /** - * Write doughnut chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html - */ - private function writeDoughnutChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:doughnutChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '1'); - $xmlWriter->writeBlock('c:holeSize', 'val', '75'); - - $this->writeSeries($xmlWriter); - - $xmlWriter->endElement(); // c:doughnutChart - } - - /** - * Write bar chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html - */ - private function writeBarChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:barChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '0'); - $xmlWriter->writeBlock('c:barDir', 'val', 'col'); // bar|col - $xmlWriter->writeBlock('c:axId', 'val', '1'); - $xmlWriter->writeBlock('c:axId', 'val', '2'); - - $this->writeSeries($xmlWriter); - - $xmlWriter->endElement(); // c:barChart - - // Axes - $this->writeAxis($xmlWriter, 'cat'); - $this->writeAxis($xmlWriter, 'val'); - } - - /** - * Write line chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html - */ - private function writeLineChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:lineChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '0'); - $xmlWriter->writeBlock('c:axId', 'val', '1'); - $xmlWriter->writeBlock('c:axId', 'val', '2'); - - $this->writeSeries($xmlWriter); - - $xmlWriter->endElement(); // c:lineChart - - // Axes - $this->writeAxis($xmlWriter, 'cat'); - $this->writeAxis($xmlWriter, 'val'); - } - - /** - * Write area chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html - */ - private function writeAreaChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:areaChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '0'); - $xmlWriter->writeBlock('c:axId', 'val', '1'); - $xmlWriter->writeBlock('c:axId', 'val', '2'); - - $this->writeSeries($xmlWriter); - - $xmlWriter->endElement(); // c:areaChart - - // Axes - $this->writeAxis($xmlWriter, 'cat'); - $this->writeAxis($xmlWriter, 'val'); - } - - /** - * Write radar chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html - */ - private function writeRadarChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:radarChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '0'); - $xmlWriter->writeBlock('c:radarStyle', 'val', 'standard'); - $xmlWriter->writeBlock('c:axId', 'val', '1'); - $xmlWriter->writeBlock('c:axId', 'val', '2'); - - $this->writeSeries($xmlWriter); - - $xmlWriter->endElement(); // c:radarChart - - // Axes - $this->writeAxis($xmlWriter, 'cat'); - $this->writeAxis($xmlWriter, 'val'); - } - - /** - * Write scatter chart - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html - */ - private function writeScatterChart(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:scatterChart'); - - $xmlWriter->writeBlock('c:varyColors', 'val', '0'); - $xmlWriter->writeBlock('c:scatterStyle', 'val', 'lineMarker'); - $xmlWriter->writeBlock('c:axId', 'val', '1'); - $xmlWriter->writeBlock('c:axId', 'val', '2'); - - $this->writeSeries($xmlWriter, true); - - $xmlWriter->endElement(); // c:scatterChart - - // Axes - $this->writeAxis($xmlWriter, 'cat'); - $this->writeAxis($xmlWriter, 'val'); - } - /** * Write series * @@ -238,8 +167,16 @@ class Chart extends AbstractPart { $xmlWriter->startElement('c:ser'); - $xmlWriter->writeBlock('c:idx', 'val', '0'); - $xmlWriter->writeBlock('c:order', 'val', '0'); + $xmlWriter->writeBlock('c:idx', 'val', 0); + $xmlWriter->writeBlock('c:order', 'val', 0); + + if (isset($this->options['scatter'])) { + $xmlWriter->startElement('c:spPr'); + $xmlWriter->startElement('a:ln'); + $xmlWriter->writeElement('a:noFill'); + $xmlWriter->endElement(); // a:ln + $xmlWriter->endElement(); // c:spPr + } if ($scatter === true) { $this->writeSeriesItems($xmlWriter, 'xVal', $this->element->getLabels()); @@ -262,16 +199,15 @@ class Chart extends AbstractPart private function writeSeriesItems(XMLWriter $xmlWriter, $type, $values) { $types = array( - 'cat' => array('c:cat', 'c:strRef', 'c:strCache'), - 'val' => array('c:val', 'c:numRef', 'c:numCache'), - 'xVal' => array('c:xVal', 'c:strRef', 'c:strCache'), - 'yVal' => array('c:yVal', 'c:numRef', 'c:numCache'), + 'cat' => array('c:cat', 'c:strLit'), + 'val' => array('c:val', 'c:numLit'), + 'xVal' => array('c:xVal', 'c:strLit'), + 'yVal' => array('c:yVal', 'c:numLit'), ); - list($itemType, $itemRef, $itemCache) = $types[$type]; + list($itemType, $itemLit) = $types[$type]; $xmlWriter->startElement($itemType); - $xmlWriter->startElement($itemRef); - $xmlWriter->startElement($itemCache); + $xmlWriter->startElement($itemLit); $index = 0; foreach ($values as $value) { @@ -286,9 +222,7 @@ class Chart extends AbstractPart $index++; } - $xmlWriter->endElement(); // $itemCache - - $xmlWriter->endElement(); // $itemRef + $xmlWriter->endElement(); // $itemLit $xmlWriter->endElement(); // $itemType } @@ -302,8 +236,8 @@ class Chart extends AbstractPart private function writeAxis(XMLWriter $xmlWriter, $type) { $types = array( - 'cat' => array('c:catAx', '1', 'b', '2'), - 'val' => array('c:valAx', '2', 'l', '1'), + 'cat' => array('c:catAx', 1, 'b', 2), + 'val' => array('c:valAx', 2, 'l', 1), ); list($axisType, $axisId, $axisPos, $axisCross) = $types[$type]; @@ -312,6 +246,18 @@ class Chart extends AbstractPart $xmlWriter->writeBlock('c:axId', 'val', $axisId); $xmlWriter->writeBlock('c:axPos', 'val', $axisPos); $xmlWriter->writeBlock('c:crossAx', 'val', $axisCross); + $xmlWriter->writeBlock('c:auto', 'val', 1); + + if (isset($this->options['axes'])) { + $xmlWriter->writeBlock('c:delete', 'val', 0); + $xmlWriter->writeBlock('c:majorTickMark', 'val', 'none'); + $xmlWriter->writeBlock('c:minorTickMark', 'val', 'none'); + $xmlWriter->writeBlock('c:tickLblPos', 'val', 'none'); // nextTo + // $xmlWriter->writeBlock('c:crosses', 'val', 'autoZero'); + } + if (isset($this->options['radar'])) { + $xmlWriter->writeElement('c:majorGridlines'); + } $xmlWriter->startElement('c:scaling'); $xmlWriter->writeBlock('c:orientation', 'val', 'minMax'); @@ -319,13 +265,42 @@ class Chart extends AbstractPart $xmlWriter->startElement('c:spPr'); $xmlWriter->writeElement('a:noFill'); + $xmlWriter->startElement('a:ln'); $xmlWriter->startElement('a:solidFill'); - $xmlWriter->writeBlock('a:srgbClr', 'val', '0FB7'); + // $xmlWriter->writeBlock('a:srgbClr', 'val', '0FF000'); $xmlWriter->endElement(); // a:solidFill $xmlWriter->endElement(); // a:ln - $xmlWriter->endElement(); // c:crossAx - $xmlWriter->endElement(); // $type + $xmlWriter->endElement(); // c:spPr + + $xmlWriter->endElement(); // $axisType + } + + /** + * Write legend + * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Legend.html + */ + private function writeLegend(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:legend'); + $xmlWriter->writeElement('c:layout'); + $xmlWriter->writeBlock('c:legendPos', 'val', 'r'); + $xmlWriter->endElement(); // c:legend + } + + /** + * Write shape + * + * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html + */ + private function writeShape(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('c:spPr'); + $xmlWriter->startElement('a:ln'); + $xmlWriter->writeElement('a:noFill'); + $xmlWriter->endElement(); // a:ln + $xmlWriter->endElement(); // c:spPr } } From f54d9a1eb443dbb8dc631ff8eb8f25fe9bafa25c Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 12 Jun 2014 02:25:34 +0700 Subject: [PATCH 263/326] #274: Page breaks on titles and tables --- CHANGELOG.md | 1 + .../Word2007/Element/AbstractElement.php | 32 ------------------- .../Writer/Word2007/Element/Container.php | 12 ------- .../Writer/Word2007/Element/PageBreak.php | 6 ++-- src/PhpWord/Writer/Word2007/Part/Settings.php | 3 +- .../Writer/Word2007/Part/DocumentTest.php | 6 ++-- 6 files changed, 8 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b741e57..ebfd3263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme - Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo GH-261 - `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich GH-270 +- Page breaks on titles and tables - @ivanlanin GH-274 ### Deprecated diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index e17640c8..1cbf213b 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -50,13 +50,6 @@ abstract class AbstractElement */ protected $withoutP = false; - /** - * Has page break before - * - * @var bool - */ - private $pageBreakBefore = false; - /** * Write element */ @@ -96,26 +89,6 @@ abstract class AbstractElement return $this->element; } - /** - * Has page break before - * - * @return bool - */ - public function hasPageBreakBefore() - { - return $this->pageBreakBefore; - } - - /** - * Set page break before - * - * @param bool $value - */ - public function setPageBreakBefore($value = true) - { - $this->pageBreakBefore = (bool)$value; - } - /** * Start w:p DOM element * @@ -129,11 +102,6 @@ abstract class AbstractElement if (method_exists($this->element, 'getParagraphStyle')) { $this->writeParagraphStyle(); } - // PageBreak - if ($this->pageBreakBefore) { - $elementWriter = new PageBreak($this->xmlWriter, new PageBreakElement()); - $elementWriter->write(); - } } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 3dad824d..9504b7a6 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -81,21 +81,9 @@ class Container extends AbstractElement $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); $writerClass = $this->namespace . '\\' . $elementClass; - // Check it's a page break. No need to write it, instead, flag containers' - // pageBreakBefore to be assigned to the next element - if ($elementClass == 'PageBreak') { - $this->setPageBreakBefore(true); - return $elementClass; - } - if (class_exists($writerClass)) { - // Get container's page break before and reset it - $pageBreakBefore = $this->hasPageBreakBefore(); - $this->setPageBreakBefore(false); - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, $element, $withoutP); - $writer->setPageBreakBefore($pageBreakBefore); $writer->write(); } diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index 47f3feb5..be317089 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -20,9 +20,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** * PageBreak element writer * - * Originally, page break is rendered as a `w:p`, but this turns out to produce bug #150. - * As of 0.11.0, page break is rendered as a `w:r` with `w:br` type "page" and `w:lastRenderedPageBreak` - * * @since 0.10.0 */ class PageBreak extends AbstractElement @@ -36,11 +33,12 @@ class PageBreak extends AbstractElement { $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:br'); $xmlWriter->writeAttribute('w:type', 'page'); $xmlWriter->endElement(); // w:br - $xmlWriter->writeElement('w:lastRenderedPageBreak'); $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:p } } diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 784a5d1e..d8535d8c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -50,7 +50,8 @@ class Settings extends AbstractPart 'w:autofitToFirstFixedWidthCell' => '', 'w:underlineTabInNumList' => '', 'w:displayHangulFixedWidth' => '', - 'w:splitPgBreakAndParaMark' => '', + // Commented for GH-274 + // 'w:splitPgBreakAndParaMark' => '', 'w:doNotVertAlignCellWithSp' => '', 'w:doNotBreakConstrainedForcedTable' => '', 'w:doNotVertAlignInTxbx' => '', diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index de5d63e8..56be15d0 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -114,15 +114,15 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $this->assertEquals('page', $element->getAttribute('w:type')); // Title - $element = $doc->getElement('/w:document/w:body/w:p[5]/w:pPr/w:pStyle'); + $element = $doc->getElement('/w:document/w:body/w:p[6]/w:pPr/w:pStyle'); $this->assertEquals('Heading1', $element->getAttribute('w:val')); // List item - $element = $doc->getElement('/w:document/w:body/w:p[6]/w:pPr/w:numPr/w:numId'); + $element = $doc->getElement('/w:document/w:body/w:p[7]/w:pPr/w:numPr/w:numId'); $this->assertEquals(3, $element->getAttribute('w:val')); // Object - $element = $doc->getElement('/w:document/w:body/w:p[11]/w:r/w:object/o:OLEObject'); + $element = $doc->getElement('/w:document/w:body/w:p[12]/w:r/w:object/o:OLEObject'); $this->assertEquals('Embed', $element->getAttribute('Type')); } From e9f8e889f8fef4e141d14505e861d7995ad558a3 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 12 Jun 2014 02:41:49 +0700 Subject: [PATCH 264/326] #275: Recipe for adding a link within a title --- docs/recipes.rst | 22 ++++++++++++++++++++++ docs/src/documentation.md | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/docs/recipes.rst b/docs/recipes.rst index d5678a52..1b529d7b 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -65,3 +65,25 @@ Define a numbering style and title styles, and match the two styles (with ``pSty $section->addTitle('Heading 1', 1); $section->addTitle('Heading 2', 2); $section->addTitle('Heading 3', 3); + +Add a link within a title +------------------------- + +Apply 'HeadingN' paragraph style to TextRun or Link. Sample code: + +.. code-block:: php + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle(1, array('size' => 16, 'bold' => true)); + $phpWord->addTitleStyle(2, array('size' => 14, 'bold' => true)); + $phpWord->addFontStyle('Link', array('color' => '0000FF', 'underline' => 'single')); + + $section = $phpWord->addSection(); + + // Textrun + $textrun = $section->addTextRun('Heading1'); + $textrun->addText('The '); + $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord', 'Link'); + + // Link + $section->addLink('https://github.com/', 'GitHub', 'Link', 'Heading2'); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 144222c1..49505c7f 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -1017,6 +1017,27 @@ $section->addTitle('Heading 2', 2); $section->addTitle('Heading 3', 3); ``` +## Add a link within a title + +Apply 'HeadingN' paragraph style to TextRun or Link. Sample code: + +```php +$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord->addTitleStyle(1, array('size' => 16, 'bold' => true)); +$phpWord->addTitleStyle(2, array('size' => 14, 'bold' => true)); +$phpWord->addFontStyle('Link', array('color' => '0000FF', 'underline' => 'single')); + +$section = $phpWord->addSection(); + +// Textrun +$textrun = $section->addTextRun('Heading1'); +$textrun->addText('The '); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord', 'Link'); + +// Link +$section->addLink('https://github.com/', 'GitHub', 'Link', 'Heading2'); +``` + # Frequently asked questions ## Is this the same with PHPWord that I found in CodePlex? From 8c2b099dbc428ce6dfb473023f91b472ce5659ab Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 14 Jun 2014 07:19:00 +0700 Subject: [PATCH 265/326] Merge `Shared\Drawing` and `Shared\Font` into `Shared\Converter` --- CHANGELOG.md | 3 + docs/general.rst | 6 +- docs/src/documentation.md | 6 +- samples/Sample_08_ParagraphPagination.php | 2 +- samples/Sample_13_Images.php | 12 +- samples/Sample_29_Line.php | 20 +- src/PhpWord/Shared/Converter.php | 245 ++++++++++++++++++ src/PhpWord/Shared/Drawing.php | 66 +---- src/PhpWord/Shared/Font.php | 21 +- src/PhpWord/Writer/ODText/Element/Image.php | 6 +- src/PhpWord/Writer/RTF/Element/Image.php | 6 +- src/PhpWord/Writer/RTF/Part/Header.php | 4 +- .../Word2007/Element/AbstractElement.php | 1 - tests/PhpWord/Tests/Element/LineTest.php | 16 +- tests/PhpWord/Tests/Element/TextBoxTest.php | 8 +- tests/PhpWord/Tests/Shared/ConverterTest.php | 108 ++++++++ tests/PhpWord/Tests/Shared/DrawingTest.php | 82 ------ tests/PhpWord/Tests/Shared/FontTest.php | 58 ----- 18 files changed, 424 insertions(+), 246 deletions(-) create mode 100644 src/PhpWord/Shared/Converter.php create mode 100644 tests/PhpWord/Tests/Shared/ConverterTest.php delete mode 100644 tests/PhpWord/Tests/Shared/DrawingTest.php delete mode 100644 tests/PhpWord/Tests/Shared/FontTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ebfd3263..5290ccb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme - RTF Writer: Support for sections, margins, and borders - @ivanlanin GH-249 - Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin GH-249 - General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin +- General: New `Shared\Converter` static class - @ivanlanin ### Bugfixes @@ -25,6 +26,8 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme - `Element\Link::getTarget()` replaced by `Element\Link::getSource()` - `Element\Section::getSettings()` and `Element\Section::setSettings()` replaced by `Element\Section::getStyle()` and `Element\Section::setStyle()` +- `Shared\Drawing` and `Shared\Font` merged into `Shared\Converter` + ### Miscellaneous diff --git a/docs/general.rst b/docs/general.rst index 60d9b609..a2498aff 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -130,13 +130,13 @@ points to twips. // Paragraph with 6 points space after $phpWord->addParagraphStyle('My Style', array( - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Font::pointSizeToTwips(6)) + 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(6)) ); $section = $phpWord->addSection(); $sectionStyle = $section->getStyle(); // half inch left margin - $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); + $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin - $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Font::centimeterSizeToTwips(2)); + $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 49505c7f..6ad2f67a 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -301,15 +301,15 @@ You can use PHPWord helper functions to convert inches, centimeters, or points t ```php // Paragraph with 6 points space after $phpWord->addParagraphStyle('My Style', array( - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Font::pointSizeToTwips(6)) + 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(6)) ); $section = $phpWord->addSection(); $sectionStyle = $section->getStyle(); // half inch left margin -$sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); +$sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin -$sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Font::centimeterSizeToTwips(2)); +$sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); ``` # Containers diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index d3f0c1fb..f3914758 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -6,7 +6,7 @@ echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle(array( 'align' => 'both', - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Font::pointSizeToTwips(12), + 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), 'spacing' => 120, )); diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index dd0c8801..29b3e733 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -37,14 +37,14 @@ $section->addText('Absolute positioning: see top right corner of page'); $section->addImage( 'resources/_mars.jpg', array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_RIGHT, 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, - 'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(15.5), - 'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(1.55) + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15.5), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1.55) ) ); @@ -55,8 +55,8 @@ $section->addText('Vertical position top relative to line'); $section->addImage( 'resources/_mars.jpg', array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE, 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, diff --git a/samples/Sample_29_Line.php b/samples/Sample_29_Line.php index 5a955702..f9162c2a 100644 --- a/samples/Sample_29_Line.php +++ b/samples/Sample_29_Line.php @@ -13,16 +13,16 @@ $section = $phpWord->addSection(); $section->addText('Horizontal Line (Inline style):'); $section->addLine( array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(0), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), 'positioning' => 'absolute' ) ); $section->addText('Vertical Line (Inline style):'); $section->addLine( array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(0), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(1), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), 'positioning' => 'absolute' ) ); @@ -32,13 +32,13 @@ $section->addTextBreak(1); $section->addText('Positioned Line (red):'); $section->addLine( array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(1), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), 'positioning' => 'absolute', 'posHorizontalRel' => 'page', 'posVerticalRel' => 'page', - 'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(10), - 'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(8), + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(10), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, 'color' => 'red' ) @@ -47,8 +47,8 @@ $section->addLine( $section->addText('Horizontal Formatted Line'); $section->addLine( array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(15), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(0), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), 'positioning' => 'absolute', 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php new file mode 100644 index 00000000..8bc1cecf --- /dev/null +++ b/src/PhpWord/Shared/Converter.php @@ -0,0 +1,245 @@ +getMediaIndex(); $target = 'Pictures/' . $element->getTarget(); $style = $element->getStyle(); - $width = Drawing::pixelsToCentimeters($style->getWidth()); - $height = Drawing::pixelsToCentimeters($style->getHeight()); + $width = Converter::pixelToCm($style->getWidth()); + $height = Converter::pixelToCm($style->getHeight()); $xmlWriter->startElement('text:p'); $xmlWriter->writeAttribute('text:style-name', 'Standard'); diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index 1daae2a0..52e705e9 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\PhpWord\Element\Image as ImageElement; -use PhpOffice\PhpWord\Shared\Font; +use PhpOffice\PhpWord\Shared\Converter; /** * Image element RTF writer @@ -45,8 +45,8 @@ class Image extends AbstractElement $content .= $this->writeOpening(); $content .= '{\*\shppict {\pict'; $content .= '\pngblip\picscalex100\picscaley100'; - $content .= '\picwgoal' . round(Font::pixelSizeToTwips($style->getWidth())); - $content .= '\pichgoal' . round(Font::pixelSizeToTwips($style->getHeight())); + $content .= '\picwgoal' . round(Converter::pixelToTwip($style->getWidth())); + $content .= '\pichgoal' . round(Converter::pixelToTwip($style->getHeight())); $content .= PHP_EOL; $content .= $this->element->getImageStringData(); $content .= '}}'; diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 4d8d3a27..68cf1803 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Shared\Drawing; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; @@ -151,7 +151,7 @@ class Header extends AbstractPart $content .= '{'; $content .= '\colortbl;'; foreach ($this->colorTable as $color) { - list($red, $green, $blue) = Drawing::htmlToRGB($color); + list($red, $green, $blue) = Converter::htmlToRgb($color); $content .= "\\red{$red}\\green{$green}\\blue{$blue};"; } $content .= '}'; diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 1cbf213b..b98b983d 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Element\AbstractElement as Element; -use PhpOffice\PhpWord\Element\PageBreak as PageBreakElement; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/tests/PhpWord/Tests/Element/LineTest.php b/tests/PhpWord/Tests/Element/LineTest.php index 429f9df6..5add9a6b 100644 --- a/tests/PhpWord/Tests/Element/LineTest.php +++ b/tests/PhpWord/Tests/Element/LineTest.php @@ -37,17 +37,17 @@ class LineTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Line', $oLine); $this->assertEquals($oLine->getStyle(), null); } - + /** * Get style name */ public function testStyleText() { $oLine = new Line('lineStyle'); - + $this->assertEquals($oLine->getStyle(), 'lineStyle'); } - + /** * Get style array */ @@ -55,14 +55,14 @@ class LineTest extends \PHPUnit_Framework_TestCase { $oLine = new Line( array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(14), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(14), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), 'positioning' => 'absolute', 'posHorizontalRel' => 'page', 'posVerticalRel' => 'page', 'flip' => true, - 'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(5), - 'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3), + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(5), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, @@ -70,7 +70,7 @@ class LineTest extends \PHPUnit_Framework_TestCase 'weight' => 10 ) ); - + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Line', $oLine->getStyle()); } } diff --git a/tests/PhpWord/Tests/Element/TextBoxTest.php b/tests/PhpWord/Tests/Element/TextBoxTest.php index c3c89ed4..2c6da465 100644 --- a/tests/PhpWord/Tests/Element/TextBoxTest.php +++ b/tests/PhpWord/Tests/Element/TextBoxTest.php @@ -55,11 +55,11 @@ class TextBoxTest extends \PHPUnit_Framework_TestCase { $oTextBox = new TextBox( array( - 'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(4.5), - 'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(17.5), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4.5), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(17.5), 'positioning' => 'absolute', - 'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(15.4), - 'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(9.9), + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15.4), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(9.9), 'stroke' => 0, 'innerMargin' => 0, 'borderSize' => 1, diff --git a/tests/PhpWord/Tests/Shared/ConverterTest.php b/tests/PhpWord/Tests/Shared/ConverterTest.php new file mode 100644 index 00000000..9525148c --- /dev/null +++ b/tests/PhpWord/Tests/Shared/ConverterTest.php @@ -0,0 +1,108 @@ +assertEquals($value / 2.54 * 1440, $result); + + $result = Converter::cmToInch($value); + $this->assertEquals($value / 2.54, $result); + + $result = Converter::cmToPixel($value); + $this->assertEquals($value / 2.54 * 96, $result); + + $result = Converter::inchToTwip($value); + $this->assertEquals($value * 1440, $result); + + $result = Converter::inchToCm($value); + $this->assertEquals($value * 2.54, $result); + + $result = Converter::inchToPixel($value); + $this->assertEquals($value * 96, $result); + + $result = Converter::inchToPoint($value); + $this->assertEquals($value * 72, $result); + + $result = Converter::pixelToTwip($value); + $this->assertEquals($value / 96 * 1440, $result); + + $result = Converter::pixelToCm($value); + $this->assertEquals($value / 96 * 2.54, $result); + + $result = Converter::pixelToPoint($value); + $this->assertEquals($value / 96 * 72, $result); + + $result = Converter::pixelToEMU($value); + $this->assertEquals(round($value * 9525), $result); + + $result = Converter::pointToTwip($value); + $this->assertEquals($value * 20, $result); + + $result = Converter::pointToPixel($value); + $this->assertEquals($value / 72 * 96, $result); + + $result = Converter::pointToEMU($value); + $this->assertEquals(round($value / 72 * 96 * 9525), $result); + + $result = Converter::emuToPixel($value); + $this->assertEquals(round($value / 9525), $result); + + $result = Converter::degreeToAngle($value); + $this->assertEquals((int)round($value * 60000), $result); + + $result = Converter::angleToDegree($value); + $this->assertEquals(round($value / 60000), $result); + } + } + + /** + * Test htmlToRGB() + */ + public function testHtmlToRGB() + { + // Prepare test values [ original, expected ] + $values[] = array('#FF99DD', array(255, 153, 221)); // With # + $values[] = array('FF99DD', array(255, 153, 221)); // 6 characters + $values[] = array('F9D', array(255, 153, 221)); // 3 characters + $values[] = array('0F9D', false); // 4 characters + // Conduct test + foreach ($values as $value) { + $result = Converter::htmlToRGB($value[0]); + $this->assertEquals($value[1], $result); + } + } +} diff --git a/tests/PhpWord/Tests/Shared/DrawingTest.php b/tests/PhpWord/Tests/Shared/DrawingTest.php deleted file mode 100644 index 25fd3a38..00000000 --- a/tests/PhpWord/Tests/Shared/DrawingTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertEquals(round($value * 9525), $result); - - $result = Drawing::emuToPixels($value); - $this->assertEquals(round($value / 9525), $result); - - $result = Drawing::pixelsToPoints($value); - $this->assertEquals($value * 0.75, $result); - - $result = Drawing::pointsToPixels($value); - $this->assertEquals($value * 1.333333333, $result); - - $result = Drawing::degreesToAngle($value); - $this->assertEquals((int)round($value * 60000), $result); - - $result = Drawing::angleToDegrees($value); - $this->assertEquals(round($value / 60000), $result); - - $result = Drawing::pixelsToCentimeters($value); - $this->assertEquals($value * 0.026458333, $result); - - $result = Drawing::centimetersToPixels($value); - $this->assertEquals($value / 0.026458333, $result); - } - } - - /** - * Test htmlToRGB() - */ - public function testHtmlToRGB() - { - // Prepare test values [ original, expected ] - $values[] = array('#FF99DD', array(255, 153, 221)); // With # - $values[] = array('FF99DD', array(255, 153, 221)); // 6 characters - $values[] = array('F9D', array(255, 153, 221)); // 3 characters - $values[] = array('0F9D', false); // 4 characters - // Conduct test - foreach ($values as $value) { - $result = Drawing::htmlToRGB($value[0]); - $this->assertEquals($value[1], $result); - } - } -} diff --git a/tests/PhpWord/Tests/Shared/FontTest.php b/tests/PhpWord/Tests/Shared/FontTest.php deleted file mode 100644 index c10f7739..00000000 --- a/tests/PhpWord/Tests/Shared/FontTest.php +++ /dev/null @@ -1,58 +0,0 @@ -assertEquals($original * 16 / 12, $result); - - $result = Font::inchSizeToPixels($original); - $this->assertEquals($original * 96, $result); - - $result = Font::centimeterSizeToPixels($original); - $this->assertEquals($original * 37.795275591, $result); - - $result = Font::centimeterSizeToTwips($original); - $this->assertEquals($original * 565.217, $result); - - $result = Font::inchSizeToTwips($original); - $this->assertEquals($original * 565.217 * 2.54, $result); - - $result = Font::pixelSizeToTwips($original); - $this->assertEquals($original * 565.217 / 37.795275591, $result); - - $result = Font::pointSizeToTwips($original); - $this->assertEquals($original * 20, $result); - } -} From 3fef19093c9deaf8bdcb024bfad056451c0e0bdd Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 12 Jun 2014 18:15:00 +0700 Subject: [PATCH 266/326] #278: Basic chart --- CHANGELOG.md | 1 + README.md | 2 + docs/elements.rst | 7 + docs/intro.rst | 2 + docs/src/documentation.md | 8 + samples/Sample_32_Chart.php | 22 ++- src/PhpWord/Element/Chart.php | 67 +++------ src/PhpWord/Shared/XMLWriter.php | 2 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 4 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 142 +++++++++--------- tests/PhpWord/Tests/Writer/RTFTest.php | 2 +- .../Tests/Writer/Word2007/ElementTest.php | 26 ++++ 12 files changed, 156 insertions(+), 129 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebfd3263..302cbf98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) eleme - RTF Writer: Support for sections, margins, and borders - @ivanlanin GH-249 - Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin GH-249 - General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin +- Element: Basic 2D charts (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 ### Bugfixes diff --git a/README.md b/README.md index 97e5b642..5a432cba 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your - Insert list items as bulleted, numbered, or multilevel - Insert hyperlinks - Insert footnotes and endnotes +- Insert drawing shapes (arc, curve, line, polyline, rect, oval) +- Insert charts (pie, doughnut, bar, line, area, scatter, radar) - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template - ... and many more features on progress diff --git a/docs/elements.rst b/docs/elements.rst index a01c9fd4..ee827326 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -49,6 +49,8 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 20 | Shape | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 21 | Chart | v | - | - | - | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -399,3 +401,8 @@ Shapes ------ To be completed. + +Charts +------ + +To be completed. diff --git a/docs/intro.rst b/docs/intro.rst index 5045d4dc..241b581c 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -45,6 +45,8 @@ Features - Insert list items as bulleted, numbered, or multilevel - Insert hyperlinks - Insert footnotes and endnotes +- Insert drawing shapes (arc, curve, line, polyline, rect, oval) +- Insert charts (pie, doughnut, bar, line, area, scatter, radar) - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 49505c7f..0b21f634 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -37,6 +37,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [Fields](#fields) - [Lines](#lines) - [Shapes](#shapes) + - [Charts](#charts) - [Styles](#styles) - [Section](#section) - [Font](#font) @@ -76,6 +77,8 @@ PHPWord is an open source project licensed under the terms of [LGPL version 3](h - Insert list items as bulleted, numbered, or multilevel - Insert hyperlinks - Insert footnotes and endnotes +- Insert drawing shapes (arc, curve, line, polyline, rect, oval) +- Insert charts (pie, doughnut, bar, line, area, scatter, radar) - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template - ... and many more features on progress @@ -440,6 +443,7 @@ Below are the matrix of element availability in each container. The column shows | 18 | Field | v | v | v | v | v | v | | 19 | Line | v | v | v | v | v | v | | 20 | Shape | v | v | v | v | v | v | +| 21 | Chart | v | - | - | - | - | - | Legend: @@ -737,6 +741,10 @@ To be completed. To be completed. +## Charts + +To be completed. + # Styles ## Section diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index 52c19f3c..26d6c420 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -9,13 +9,23 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(array('colsNum' => 2)); $phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240)); -$charts = array('pie', 'doughnut', 'line', 'area', 'scatter', 'bar', 'radar'); -$labels = array('A', 'B', 'C', 'D', 'E'); -$data = array(1, 3, 2, 5, 4); +$chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); +$twoSeries = array('bar', 'line', 'area', 'scatter', 'radar'); +$threeSeries = array('bar', 'line'); +$categories = array('A', 'B', 'C', 'D', 'E'); +$series1 = array(1, 3, 2, 5, 4); +$series2 = array(3, 1, 7, 2, 6); +$series3 = array(8, 3, 2, 5, 4); -foreach ($charts as $chart) { - $section->addTitle(ucfirst($chart), 1); - $section->addChart($chart, $labels, $data); +foreach ($chartTypes as $chartType) { + $section->addTitle(ucfirst($chartType), 1); + $chart = $section->addChart($chartType, $categories, $series1); + if (in_array($chartType, $twoSeries)) { + $chart->addSeries($categories, $series2); + } + if (in_array($chartType, $threeSeries)) { + $chart->addSeries($categories, $series3); + } $section->addTextBreak(); } diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 5a93b827..24f2bb78 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -39,31 +39,23 @@ class Chart extends AbstractElement private $type = 'pie'; /** - * Labels + * Series * * @var array */ - private $labels = array(); - - /** - * Data - * - * @var array - */ - private $data = array(); + private $series = array(); /** * Create new instance * * @param string $type - * @param array $labels - * @param array $data + * @param array $categories + * @param array $values */ - public function __construct($type, $labels, $data) + public function __construct($type, $categories, $values) { $this->setType($type); - $this->setLabels($labels); - $this->setData($data); + $this->addSeries($categories, $values); } /** @@ -88,42 +80,23 @@ class Chart extends AbstractElement } /** - * Get labels + * Add series + * + * @param array $categories + * @param array $values + */ + public function addSeries($categories, $values) + { + $this->series[] = array('categories' => $categories, 'values' => $values); + } + + /** + * Get series * * @return array */ - public function getLabels() + public function getSeries() { - return $this->labels; - } - - /** - * Set labels - * - * @param array $value - */ - public function setLabels($value) - { - $this->labels = $value; - } - - /** - * Get data - * - * @return array - */ - public function getData() - { - return $this->data; - } - - /** - * Set data - * - * @param array $value - */ - public function setData($value) - { - $this->data = $value; + return $this->series; } } diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index b2057bb9..8691ae1d 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -150,7 +150,7 @@ class XMLWriter * @param string|array $attributes * @param string $value */ - public function writeBlock($element, $attributes, $value = null) + public function writeElementBlock($element, $attributes, $value = null) { $this->xmlWriter->startElement($element); if (!is_array($attributes)) { diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 454ebce5..4330e2fe 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -48,8 +48,8 @@ class Chart extends AbstractElement $xmlWriter->startElement('wp:inline'); // EMU - $xmlWriter->writeBlock('wp:extent', array('cx' => '2000000', 'cy' => '2000000')); - $xmlWriter->writeBlock('wp:docPr', array('id' => $rId, 'name' => "Chart{$rId}")); + $xmlWriter->writeElementBlock('wp:extent', array('cx' => '2000000', 'cy' => '2000000')); + $xmlWriter->writeElementBlock('wp:docPr', array('id' => $rId, 'name' => "Chart{$rId}")); $xmlWriter->startElement('a:graphic'); $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 8d922013..66e43914 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -25,7 +25,6 @@ use PhpOffice\PhpWord\Element\Chart as ChartElement; * * @since 0.12.0 * @link http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class Chart extends AbstractPart { @@ -36,6 +35,11 @@ class Chart extends AbstractPart */ private $element; + /** + * Type definition + * + * @var array + */ private $types = array( 'pie' => array('type' => 'pieChart', 'colors' => 1), 'doughnut' => array('type' => 'doughnutChart', 'colors' => 1, 'hole' => 75), @@ -46,6 +50,11 @@ class Chart extends AbstractPart 'scatter' => array('type' => 'scatterChart', 'colors' => 0, 'axes' => true, 'scatter' => 'marker'), ); + /** + * Chart options + * + * @var array + */ private $options = array(); /** @@ -71,14 +80,9 @@ class Chart extends AbstractPart $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeBlock('c:date1904', 'val', 1); - $xmlWriter->writeBlock('c:lang', 'val', 'en-US'); - $xmlWriter->writeBlock('c:roundedCorners', 'val', 0); - $this->writeChart($xmlWriter); $this->writeShape($xmlWriter); - $xmlWriter->endElement(); // c:chartSpace return $xmlWriter->getData(); @@ -93,11 +97,9 @@ class Chart extends AbstractPart { $xmlWriter->startElement('c:chart'); - $xmlWriter->writeBlock('c:autoTitleDeleted', 'val', 1); - $xmlWriter->writeBlock('c:dispBlanksAs', 'val', 'zero'); + $xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1); $this->writePlotArea($xmlWriter); - // $this->writeLegend($xmlWriter); $xmlWriter->endElement(); // c:chart } @@ -125,27 +127,33 @@ class Chart extends AbstractPart // Chart $xmlWriter->startElement('c:' . $this->options['type']); - $xmlWriter->writeBlock('c:varyColors', 'val', $this->options['colors']); + $xmlWriter->writeElementBlock('c:varyColors', 'val', $this->options['colors']); + if ($type == 'area') { + $xmlWriter->writeElementBlock('c:grouping', 'val', 'standard'); + } if (isset($this->options['hole'])) { - $xmlWriter->writeBlock('c:holeSize', 'val', $this->options['hole']); + $xmlWriter->writeElementBlock('c:holeSize', 'val', $this->options['hole']); } if (isset($this->options['bar'])) { - $xmlWriter->writeBlock('c:barDir', 'val', $this->options['bar']); // bar|col + $xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col + $xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); } if (isset($this->options['radar'])) { - $xmlWriter->writeBlock('c:radarStyle', 'val', $this->options['radar']); + $xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']); } if (isset($this->options['scatter'])) { - $xmlWriter->writeBlock('c:scatterStyle', 'val', $this->options['scatter']); - } - if (isset($this->options['axes'])) { - $xmlWriter->writeBlock('c:axId', 'val', 1); - $xmlWriter->writeBlock('c:axId', 'val', 2); + $xmlWriter->writeElementBlock('c:scatterStyle', 'val', $this->options['scatter']); } // Series $this->writeSeries($xmlWriter, isset($this->options['scatter'])); + // Axes + if (isset($this->options['axes'])) { + $xmlWriter->writeElementBlock('c:axId', 'val', 1); + $xmlWriter->writeElementBlock('c:axId', 'val', 2); + } + $xmlWriter->endElement(); // chart type // Axes @@ -165,28 +173,34 @@ class Chart extends AbstractPart */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) { - $xmlWriter->startElement('c:ser'); + $series = $this->element->getSeries(); - $xmlWriter->writeBlock('c:idx', 'val', 0); - $xmlWriter->writeBlock('c:order', 'val', 0); + $index = 0; + foreach ($series as $seriesItem) { + $categories = $seriesItem['categories']; + $values = $seriesItem['values']; - if (isset($this->options['scatter'])) { - $xmlWriter->startElement('c:spPr'); - $xmlWriter->startElement('a:ln'); - $xmlWriter->writeElement('a:noFill'); - $xmlWriter->endElement(); // a:ln - $xmlWriter->endElement(); // c:spPr + $xmlWriter->startElement('c:ser'); + + $xmlWriter->writeElementBlock('c:idx', 'val', $index); + $xmlWriter->writeElementBlock('c:order', 'val', $index); + + if (isset($this->options['scatter'])) { + $this->writeShape($xmlWriter); + } + + if ($scatter === true) { + $this->writeSeriesItem($xmlWriter, 'xVal', $categories); + $this->writeSeriesItem($xmlWriter, 'yVal', $values); + } else { + $this->writeSeriesItem($xmlWriter, 'cat', $categories); + $this->writeSeriesItem($xmlWriter, 'val', $values); + } + + $xmlWriter->endElement(); // c:ser + $index++; } - if ($scatter === true) { - $this->writeSeriesItems($xmlWriter, 'xVal', $this->element->getLabels()); - $this->writeSeriesItems($xmlWriter, 'yVal', $this->element->getData()); - } else { - $this->writeSeriesItems($xmlWriter, 'cat', $this->element->getLabels()); - $this->writeSeriesItems($xmlWriter, 'val', $this->element->getData()); - } - - $xmlWriter->endElement(); // c:ser } /** @@ -196,7 +210,7 @@ class Chart extends AbstractPart * @param string $type * @param array $values */ - private function writeSeriesItems(XMLWriter $xmlWriter, $type, $values) + private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) { $types = array( 'cat' => array('c:cat', 'c:strLit'), @@ -243,63 +257,47 @@ class Chart extends AbstractPart $xmlWriter->startElement($axisType); - $xmlWriter->writeBlock('c:axId', 'val', $axisId); - $xmlWriter->writeBlock('c:axPos', 'val', $axisPos); - $xmlWriter->writeBlock('c:crossAx', 'val', $axisCross); - $xmlWriter->writeBlock('c:auto', 'val', 1); + $xmlWriter->writeElementBlock('c:axId', 'val', $axisId); + $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); + $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross); + $xmlWriter->writeElementBlock('c:auto', 'val', 1); if (isset($this->options['axes'])) { - $xmlWriter->writeBlock('c:delete', 'val', 0); - $xmlWriter->writeBlock('c:majorTickMark', 'val', 'none'); - $xmlWriter->writeBlock('c:minorTickMark', 'val', 'none'); - $xmlWriter->writeBlock('c:tickLblPos', 'val', 'none'); // nextTo - // $xmlWriter->writeBlock('c:crosses', 'val', 'autoZero'); + $xmlWriter->writeElementBlock('c:delete', 'val', 0); + $xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none'); + $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none'); + $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); // nextTo + $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero'); } if (isset($this->options['radar'])) { $xmlWriter->writeElement('c:majorGridlines'); } $xmlWriter->startElement('c:scaling'); - $xmlWriter->writeBlock('c:orientation', 'val', 'minMax'); + $xmlWriter->writeElementBlock('c:orientation', 'val', 'minMax'); $xmlWriter->endElement(); // c:scaling - $xmlWriter->startElement('c:spPr'); - $xmlWriter->writeElement('a:noFill'); - - $xmlWriter->startElement('a:ln'); - $xmlWriter->startElement('a:solidFill'); - // $xmlWriter->writeBlock('a:srgbClr', 'val', '0FF000'); - $xmlWriter->endElement(); // a:solidFill - $xmlWriter->endElement(); // a:ln - - $xmlWriter->endElement(); // c:spPr + $this->writeShape($xmlWriter, true); $xmlWriter->endElement(); // $axisType } - /** - * Write legend - * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Legend.html - */ - private function writeLegend(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('c:legend'); - $xmlWriter->writeElement('c:layout'); - $xmlWriter->writeBlock('c:legendPos', 'val', 'r'); - $xmlWriter->endElement(); // c:legend - } - /** * Write shape * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param bool $line * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html */ - private function writeShape(XMLWriter $xmlWriter) + private function writeShape(XMLWriter $xmlWriter, $line = false) { $xmlWriter->startElement('c:spPr'); $xmlWriter->startElement('a:ln'); - $xmlWriter->writeElement('a:noFill'); + if ($line === true) { + $xmlWriter->writeElement('a:solidFill'); + } else { + $xmlWriter->writeElement('a:noFill'); + } $xmlWriter->endElement(); // a:ln $xmlWriter->endElement(); // c:spPr } diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index c1448106..5b983b35 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -91,7 +91,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase $this->assertTrue(file_exists($file)); - unlink($file); + @unlink($file); } /** diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 2e76df12..0ba29f2f 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -148,4 +148,30 @@ class ElementTest extends \PHPUnit_Framework_TestCase $this->assertTrue($doc->elementExists($path)); } } + + /** + * Test shape elements + */ + public function testChartElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + foreach ($chartTypes as $chartType) { + $section->addChart($chartType, $categories, $series1); + } + + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 0; + foreach ($chartTypes as $chartType) { + $index++; + $file = "word/charts/chart{$index}.xml"; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + $this->assertTrue($doc->elementExists($path, $file)); + } + } } From a13e5b20f98969f6e4ca44d8ab8d4e6180c60501 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 15 Jun 2014 20:48:26 +0700 Subject: [PATCH 267/326] #278: 3D charts and ability to set width and height --- CHANGELOG.md | 3 +- samples/Sample_32_Chart.php | 37 ++++- src/PhpWord/Element/Chart.php | 25 +++- src/PhpWord/Shared/Converter.php | 33 +++++ src/PhpWord/Style/AbstractStyle.php | 4 +- src/PhpWord/Style/Chart.php | 127 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/Chart.php | 3 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 23 ++-- tests/PhpWord/Tests/Shared/ConverterTest.php | 9 ++ .../Tests/Writer/Word2007/ElementTest.php | 3 +- 10 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 src/PhpWord/Style/Chart.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c646ac..155ecb35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) and b - Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin GH-249 - General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin - General: New `Shared\Converter` static class - @ivanlanin -- Element: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 +- Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 +- Chart: 3D charts and ability to set width and height - @ivanlanin ### Bugfixes diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index 26d6c420..5f2188ed 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -1,16 +1,22 @@ addSection(array('colsNum' => 2)); $phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240)); +$phpWord->addTitleStyle(2, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240)); -$chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); -$twoSeries = array('bar', 'line', 'area', 'scatter', 'radar'); +// 2D charts +$section = $phpWord->addSection(); +$section->addTitle('2D charts', 1); +$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); + +$chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar'); +$twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar'); $threeSeries = array('bar', 'line'); $categories = array('A', 'B', 'C', 'D', 'E'); $series1 = array(1, 3, 2, 5, 4); @@ -18,8 +24,11 @@ $series2 = array(3, 1, 7, 2, 6); $series3 = array(8, 3, 2, 5, 4); foreach ($chartTypes as $chartType) { - $section->addTitle(ucfirst($chartType), 1); + $section->addTitle(ucfirst($chartType), 2); $chart = $section->addChart($chartType, $categories, $series1); + $chart->getStyle() + ->setWidth(Converter::inchToEmu(2.5)) + ->setHeight(Converter::inchToEmu(2)); if (in_array($chartType, $twoSeries)) { $chart->addSeries($categories, $series2); } @@ -29,6 +38,24 @@ foreach ($chartTypes as $chartType) { $section->addTextBreak(); } +// 3D charts +$section = $phpWord->addSection(array('breakType' => 'continuous')); +$section->addTitle('3D charts', 1); +$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); + +$chartTypes = array('pie', 'bar', 'column', 'line', 'area'); +$multiSeries = array('bar', 'column', 'line', 'area'); +$style = array('width' => Converter::cmToEmu(5), 'height' => Converter::cmToEmu(4), '3d' => true); +foreach ($chartTypes as $chartType) { + $section->addTitle(ucfirst($chartType), 2); + $chart = $section->addChart($chartType, $categories, $series1, $style); + if (in_array($chartType, $multiSeries)) { + $chart->addSeries($categories, $series2); + $chart->addSeries($categories, $series3); + } + $section->addTextBreak(); +} + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 24f2bb78..629db63b 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Chart as ChartStyle; + + /** * Chart element * @@ -45,6 +48,13 @@ class Chart extends AbstractElement */ private $series = array(); + /** + * Chart style + * + * @var \PhpOffice\PhpWord\Style\Chart + */ + private $style; + /** * Create new instance * @@ -52,10 +62,11 @@ class Chart extends AbstractElement * @param array $categories * @param array $values */ - public function __construct($type, $categories, $values) + public function __construct($type, $categories, $values, $style = null) { $this->setType($type); $this->addSeries($categories, $values); + $this->style = $this->setNewStyle(new ChartStyle(), $style, true); } /** @@ -75,7 +86,7 @@ class Chart extends AbstractElement */ public function setType($value) { - $enum = array('pie', 'doughnut', 'line', 'bar', 'area', 'radar', 'scatter'); + $enum = array('pie', 'doughnut', 'line', 'bar', 'column', 'area', 'radar', 'scatter'); $this->type = $this->setEnumVal($value, $enum, 'pie'); } @@ -99,4 +110,14 @@ class Chart extends AbstractElement { return $this->series; } + + /** + * Get chart style + * + * @return \PhpOffice\PhpWord\Style\Chart + */ + public function getStyle() + { + return $this->style; + } } diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 8bc1cecf..c6727edd 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -62,6 +62,28 @@ class Converter return $centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL; } + /** + * Convert centimeter to point + * + * @param int $centimeter + * @return float + */ + public static function cmToPoint($centimeter = 1) + { + return $centimeter / self::INCH_TO_CM * self::INCH_TO_POINT; + } + + /** + * Convert centimeter to EMU + * + * @param int $centimeter + * @return int + */ + public static function cmToEmu($centimeter = 1) + { + return round($centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU); + } + /** * Convert inch to twip * @@ -106,6 +128,17 @@ class Converter return $inch * self::INCH_TO_POINT; } + /** + * Convert inch to EMU + * + * @param int $inch + * @return int + */ + public static function inchToEmu($inch = 1) + { + return round($inch * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU); + } + /** * Convert pixel to twip * diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index cc275fc6..6f527210 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -244,8 +244,10 @@ abstract class AbstractStyle if (is_string($value) && (preg_match('/[^\d]/', $value) == 0)) { $value = intval($value); } - if (!is_int($value)) { + if (!is_numeric($value)) { $value = $default; + } else { + $value = intval($value); } return $value; diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php new file mode 100644 index 00000000..13b72a33 --- /dev/null +++ b/src/PhpWord/Style/Chart.php @@ -0,0 +1,127 @@ +setStyleByArray($style); + } + + /** + * Get width + * + * @return int + */ + public function getWidth() + { + return $this->width; + } + + /** + * Set width + * + * @param int $value + * @return self + */ + public function setWidth($value = null) + { + $this->width = $this->setIntVal($value, $this->width); + + return $this; + } + + /** + * Get height + * + * @return int + */ + public function getHeight() + { + return $this->height; + } + + /** + * Set height + * + * @param int $value + * @return self + */ + public function setHeight($value = null) + { + $this->height = $this->setIntVal($value, $this->height); + + return $this; + } + + /** + * Is 3D + * + * @return bool + */ + public function is3d() + { + return $this->is3d; + } + + /** + * Set 3D + * + * @param bool $value + * @return self + */ + public function set3d($value = true) + { + $this->is3d = $this->setBoolVal($value, $this->is3d); + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 4330e2fe..e185ee58 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -38,6 +38,7 @@ class Chart extends AbstractElement } $rId = $element->getRelationId(); + $style = $element->getStyle(); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); @@ -48,7 +49,7 @@ class Chart extends AbstractElement $xmlWriter->startElement('wp:inline'); // EMU - $xmlWriter->writeElementBlock('wp:extent', array('cx' => '2000000', 'cy' => '2000000')); + $xmlWriter->writeElementBlock('wp:extent', array('cx' => $style->getWidth(), 'cy' => $style->getHeight())); $xmlWriter->writeElementBlock('wp:docPr', array('id' => $rId, 'name' => "Chart{$rId}")); $xmlWriter->startElement('a:graphic'); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 66e43914..0a0ebac6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -41,13 +41,14 @@ class Chart extends AbstractPart * @var array */ private $types = array( - 'pie' => array('type' => 'pieChart', 'colors' => 1), - 'doughnut' => array('type' => 'doughnutChart', 'colors' => 1, 'hole' => 75), - 'bar' => array('type' => 'barChart', 'colors' => 0, 'axes' => true, 'bar' => 'col'), - 'line' => array('type' => 'lineChart', 'colors' => 0, 'axes' => true), - 'area' => array('type' => 'areaChart', 'colors' => 0, 'axes' => true), - 'radar' => array('type' => 'radarChart', 'colors' => 0, 'axes' => true, 'radar' => 'standard'), - 'scatter' => array('type' => 'scatterChart', 'colors' => 0, 'axes' => true, 'scatter' => 'marker'), + 'pie' => array('type' => 'pie', 'colors' => 1), + 'doughnut' => array('type' => 'doughnut', 'colors' => 1, 'hole' => 75, 'no3d' => true), + 'bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar'), + 'column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col'), + 'line' => array('type' => 'line', 'colors' => 0, 'axes' => true), + 'area' => array('type' => 'area', 'colors' => 0, 'axes' => true), + 'radar' => array('type' => 'radar', 'colors' => 0, 'axes' => true, 'radar' => 'standard', 'no3d' => true), + 'scatter' => array('type' => 'scatter', 'colors' => 0, 'axes' => true, 'scatter' => 'marker', 'no3d' => true), ); /** @@ -119,13 +120,17 @@ class Chart extends AbstractPart private function writePlotArea(XMLWriter $xmlWriter) { $type = $this->element->getType(); + $style = $this->element->getStyle(); $this->options = $this->types[$type]; $xmlWriter->startElement('c:plotArea'); $xmlWriter->writeElement('c:layout'); // Chart - $xmlWriter->startElement('c:' . $this->options['type']); + $chartType = $this->options['type']; + $chartType .= $style->is3d() && !isset($this->options['no3d'])? '3D' : ''; + $chartType .= 'Chart'; + $xmlWriter->startElement("c:{$chartType}"); $xmlWriter->writeElementBlock('c:varyColors', 'val', $this->options['colors']); if ($type == 'area') { @@ -136,7 +141,7 @@ class Chart extends AbstractPart } if (isset($this->options['bar'])) { $xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col - $xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); + $xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); // 3d; standard = percentStacked } if (isset($this->options['radar'])) { $xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']); diff --git a/tests/PhpWord/Tests/Shared/ConverterTest.php b/tests/PhpWord/Tests/Shared/ConverterTest.php index 9525148c..002e2e33 100644 --- a/tests/PhpWord/Tests/Shared/ConverterTest.php +++ b/tests/PhpWord/Tests/Shared/ConverterTest.php @@ -45,6 +45,12 @@ class ConverterTest extends \PHPUnit_Framework_TestCase $result = Converter::cmToPixel($value); $this->assertEquals($value / 2.54 * 96, $result); + $result = Converter::cmToPoint($value); + $this->assertEquals($value / 2.54 * 72, $result); + + $result = Converter::cmToEmu($value); + $this->assertEquals(round($value / 2.54 * 96 * 9525), $result); + $result = Converter::inchToTwip($value); $this->assertEquals($value * 1440, $result); @@ -57,6 +63,9 @@ class ConverterTest extends \PHPUnit_Framework_TestCase $result = Converter::inchToPoint($value); $this->assertEquals($value * 72, $result); + $result = Converter::inchToEmu($value); + $this->assertEquals(round($value * 96 * 9525), $result); + $result = Converter::pixelToTwip($value); $this->assertEquals($value / 96 * 1440, $result); diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 0ba29f2f..528cafd5 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -156,12 +156,13 @@ class ElementTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $section = $phpWord->addSection(); + $style = array('width' => 1000000, 'height' => 1000000, '3d' => true); $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); $categories = array('A', 'B', 'C', 'D', 'E'); $series1 = array(1, 3, 2, 5, 4); foreach ($chartTypes as $chartType) { - $section->addChart($chartType, $categories, $series1); + $section->addChart($chartType, $categories, $series1, $style); } $doc = TestHelperDOCX::getDocument($phpWord); From 6a81691d453c57c1215da78357b13a87636195a2 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 16 Jun 2014 00:09:14 +0700 Subject: [PATCH 268/326] #266: Ability to add textinput, checkbox, and dropdown form elements --- CHANGELOG.md | 3 +- README.md | 1 + docs/elements.rst | 7 + docs/intro.rst | 1 + docs/src/documentation.md | 7 + samples/Sample_33_FormField.php | 26 +++ src/PhpWord/Element/AbstractContainer.php | 6 +- src/PhpWord/Element/Chart.php | 2 +- src/PhpWord/Element/CheckBox.php | 2 + src/PhpWord/Element/FormField.php | 195 ++++++++++++++++++ src/PhpWord/Shared/Drawing.php | 20 +- src/PhpWord/Shared/Font.php | 18 +- .../Writer/Word2007/Element/FormField.php | 161 +++++++++++++++ .../Tests/Writer/Word2007/ElementTest.php | 25 ++- 14 files changed, 449 insertions(+), 25 deletions(-) create mode 100644 samples/Sample_33_FormField.php create mode 100644 src/PhpWord/Element/FormField.php create mode 100644 src/PhpWord/Writer/Word2007/Element/FormField.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 155ecb35..49fe9993 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.12.0 - Not yet released -This release added drawing shapes (arc, curve, line, polyline, rect, oval) and basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) elements along with some new styles. +This release added form fields (textinput, checkbox, and dropdown), drawing shapes (arc, curve, line, polyline, rect, oval), and basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) elements along with some new styles. ### Features @@ -17,6 +17,7 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) and b - General: New `Shared\Converter` static class - @ivanlanin - Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 - Chart: 3D charts and ability to set width and height - @ivanlanin +- FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin GH-266 ### Bugfixes diff --git a/README.md b/README.md index 5a432cba..825f7926 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your - Insert footnotes and endnotes - Insert drawing shapes (arc, curve, line, polyline, rect, oval) - Insert charts (pie, doughnut, bar, line, area, scatter, radar) +- Insert form fields (textinput, checkbox, and dropdown) - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template - ... and many more features on progress diff --git a/docs/elements.rst b/docs/elements.rst index ee827326..e4baf70e 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -51,6 +51,8 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 21 | Chart | v | - | - | - | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 22 | Form fields | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -406,3 +408,8 @@ Charts ------ To be completed. + +Form fields +----------- + +To be completed. diff --git a/docs/intro.rst b/docs/intro.rst index 241b581c..b604298f 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -47,6 +47,7 @@ Features - Insert footnotes and endnotes - Insert drawing shapes (arc, curve, line, polyline, rect, oval) - Insert charts (pie, doughnut, bar, line, area, scatter, radar) +- Insert form fields (textinput, checkbox, and dropdown) - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 39e61862..20996808 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -38,6 +38,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst - [Lines](#lines) - [Shapes](#shapes) - [Charts](#charts) + - [FormFields](#form-fields) - [Styles](#styles) - [Section](#section) - [Font](#font) @@ -79,6 +80,7 @@ PHPWord is an open source project licensed under the terms of [LGPL version 3](h - Insert footnotes and endnotes - Insert drawing shapes (arc, curve, line, polyline, rect, oval) - Insert charts (pie, doughnut, bar, line, area, scatter, radar) +- Insert form fields (textinput, checkbox, and dropdown) - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template - ... and many more features on progress @@ -444,6 +446,7 @@ Below are the matrix of element availability in each container. The column shows | 19 | Line | v | v | v | v | v | v | | 20 | Shape | v | v | v | v | v | v | | 21 | Chart | v | - | - | - | - | - | +| 22 | Form Fields | v | v | v | v | v | v | Legend: @@ -745,6 +748,10 @@ To be completed. To be completed. +## Form fields + +To be completed. + # Styles ## Section diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php new file mode 100644 index 00000000..f7b7c852 --- /dev/null +++ b/samples/Sample_33_FormField.php @@ -0,0 +1,26 @@ +addSection(); + +$textrun = $section->addTextRun(); +$textrun->addText('Form fields can be added in a text run and can be in form of textinput '); +$textrun->addFormField('textinput')->setName('MyTextBox'); +$textrun->addText(', checkbox '); +$textrun->addFormField('checkbox')->setDefault(true); +$textrun->addText(', or dropdown '); +$textrun->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); +$textrun->addText('. You have to set document protection to "forms" to enable dropdown.'); + +$section->addText('They can also be added as a stand alone paragraph.'); +$section->addFormField('textinput')->setValue('Your name'); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 19e78c21..3ec11390 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -41,7 +41,8 @@ namespace PhpOffice\PhpWord\Element; * @method Field addField(string $type = null, array $properties = array(), array $options = array()) * @method Line addLine(mixed $lineStyle = null) * @method Shape addObject(string $type, mixed $style = null) - * @method Chart addChart() + * @method Chart addChart(string $type, array $categories, array $values, array $style = null) + * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) * * @since 0.10.0 */ @@ -78,7 +79,7 @@ abstract class AbstractContainer extends AbstractElement $elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', - 'Title', 'TOC', 'PageBreak', 'Chart'); + 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField'); $functions = array(); for ($i = 0; $i < count($elements); $i++) { $functions[$i] = 'add' . $elements[$i]; @@ -190,6 +191,7 @@ abstract class AbstractContainer extends AbstractElement 'Field' => $allContainers, 'Line' => $allContainers, 'Shape' => $allContainers, + 'FormField' => $allContainers, 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 629db63b..2d709b8c 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -19,7 +19,6 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Chart as ChartStyle; - /** * Chart element * @@ -61,6 +60,7 @@ class Chart extends AbstractElement * @param string $type * @param array $categories * @param array $values + * @param array $style */ public function __construct($type, $categories, $values, $style = null) { diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index a5620580..d3b2a3c6 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -21,6 +21,8 @@ use PhpOffice\PhpWord\Shared\String; /** * Check box element + * + * @since 0.10.0 */ class CheckBox extends Text { diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php new file mode 100644 index 00000000..7bd61be1 --- /dev/null +++ b/src/PhpWord/Element/FormField.php @@ -0,0 +1,195 @@ +setType($type); + } + + /** + * Get type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set type + * + * @param string $value + * @return self + */ + public function setType($value) + { + $enum = array('textinput', 'checkbox', 'dropdown'); + $this->type = $this->setEnumVal($value, $enum, $this->type); + + return $this; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set name + * + * @param string|bool|int $value + * @return self + */ + public function setName($value) + { + $this->name = $value; + + return $this; + } + + /** + * Get default + * + * @return string|bool|int + */ + public function getDefault() + { + return $this->default; + } + + /** + * Set default + * + * @param string|bool|int $value + * @return self + */ + public function setDefault($value) + { + $this->default = $value; + + return $this; + } + + /** + * Get value + * + * @return string|bool|int + */ + public function getValue() + { + return $this->value; + } + + /** + * Set value + * + * @param string|bool|int $value + * @return self + */ + public function setValue($value) + { + $this->value = $value; + + return $this; + } + + /** + * Get entries + * + * @return array + */ + public function getEntries() + { + return $this->entries; + } + + /** + * Set entries + * + * @param array $value + * @return self + */ + public function setEntries($value) + { + $this->entries = $value; + + return $this; + } +} diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 00d8b565..59fbe026 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -18,12 +18,12 @@ namespace PhpOffice\PhpWord\Shared; /** - * Common drawing functions; replaced by `Converter` + * DEPRECATED: Common drawing functions; Use 'Converter' * * @deprecated 0.12.0 * @codeCoverageIgnore */ -class Drawing extends Converter +class Drawing { /** * Convert pixels to EMU @@ -33,7 +33,7 @@ class Drawing extends Converter */ public static function pixelsToEMU($value = 0) { - return self::pixelToEmu($value); + return Converter::pixelToEmu($value); } /** @@ -44,7 +44,7 @@ class Drawing extends Converter */ public static function emuToPixels($value = 0) { - return self::emuToPixel($value); + return Converter::emuToPixel($value); } /** @@ -55,7 +55,7 @@ class Drawing extends Converter */ public static function pixelsToPoints($value = 0) { - return self::pixelToPoint($value); + return Converter::pixelToPoint($value); } /** @@ -66,7 +66,7 @@ class Drawing extends Converter */ public static function pointsToPixels($value = 0) { - return self::pointToPixel($value); + return Converter::pointToPixel($value); } /** @@ -77,7 +77,7 @@ class Drawing extends Converter */ public static function degreesToAngle($value = 0) { - return self::degreeToAngle($value); + return Converter::degreeToAngle($value); } /** @@ -88,7 +88,7 @@ class Drawing extends Converter */ public static function angleToDegrees($value = 0) { - return self::angleToDegree($value); + return Converter::angleToDegree($value); } /** @@ -99,7 +99,7 @@ class Drawing extends Converter */ public static function pixelsToCentimeters($value = 0) { - return self::pixelToCm($value); + return Converter::pixelToCm($value); } /** @@ -110,6 +110,6 @@ class Drawing extends Converter */ public static function centimetersToPixels($value = 0) { - return self::cmToPixel($value); + return Converter::cmToPixel($value); } } diff --git a/src/PhpWord/Shared/Font.php b/src/PhpWord/Shared/Font.php index 6aeacef7..231b0bbd 100644 --- a/src/PhpWord/Shared/Font.php +++ b/src/PhpWord/Shared/Font.php @@ -18,12 +18,12 @@ namespace PhpOffice\PhpWord\Shared; /** - * Common font functions; replaced by `Converter` + * DEPRECATED: Common font functions; Use 'Converter' * * @deprecated 0.12.0 * @codeCoverageIgnore */ -class Font extends Converter +class Font { /** * Calculate an (approximate) pixel size, based on a font points size @@ -33,7 +33,7 @@ class Font extends Converter */ public static function fontSizeToPixels($fontSizeInPoints = 12) { - return self::pointToPixel($fontSizeInPoints); + return Converter::pointToPixel($fontSizeInPoints); } /** @@ -44,7 +44,7 @@ class Font extends Converter */ public static function inchSizeToPixels($sizeInInch = 1) { - return self::inchToPixel($sizeInInch); + return Converter::inchToPixel($sizeInInch); } /** @@ -55,7 +55,7 @@ class Font extends Converter */ public static function centimeterSizeToPixels($sizeInCm = 1) { - return self::cmToPixel($sizeInCm); + return Converter::cmToPixel($sizeInCm); } /** @@ -66,7 +66,7 @@ class Font extends Converter */ public static function centimeterSizeToTwips($sizeInCm = 1) { - return self::cmToTwip($sizeInCm); + return Converter::cmToTwip($sizeInCm); } /** @@ -77,7 +77,7 @@ class Font extends Converter */ public static function inchSizeToTwips($sizeInInch = 1) { - return self::inchToTwip($sizeInInch); + return Converter::inchToTwip($sizeInInch); } /** @@ -88,7 +88,7 @@ class Font extends Converter */ public static function pixelSizeToTwips($sizeInPixel = 1) { - return self::pixelToTwip($sizeInPixel); + return Converter::pixelToTwip($sizeInPixel); } /** @@ -99,6 +99,6 @@ class Font extends Converter */ public static function pointSizeToTwips($sizeInPoint = 1) { - return self::pointToTwip($sizeInPoint); + return Converter::pointToTwip($sizeInPoint); } } diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php new file mode 100644 index 00000000..21003314 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -0,0 +1,161 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof FormFieldElement) { + return; + } + + $type = $element->getType(); + $instructions = array('textinput' => 'FORMTEXT', 'checkbox' => 'FORMCHECKBOX', 'dropdown' => 'FORMDROPDOWN'); + $instruction = $instructions[$type]; + $writeFormField = "write{$type}"; + $name = $element->getName(); + if ($name === null) { + $name = $type . $element->getElementId(); + } + $value = $element->getValue(); + if ($value === null) { + $value = str_repeat(' ', self::FILLER_LENGTH); + } + + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->startElement('w:ffData'); + $xmlWriter->writeElementBlock('w:enabled', 'w:val', 1); + $xmlWriter->writeElementBlock('w:name', 'w:val', $name); + $xmlWriter->writeElementBlock('w:calcOnExit', 'w:val', 0); + $this->$writeFormField($xmlWriter, $element); + $xmlWriter->endElement(); // w:ffData + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw("{$instruction}"); + $xmlWriter->endElement();// w:instrText + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); + $xmlWriter->writeElementBlock('w:fldChar', 'w:fldCharType', 'separate'); + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($value); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); + $xmlWriter->writeElementBlock('w:fldChar', 'w:fldCharType', 'end'); + $xmlWriter->endElement(); // w:r + + $this->endElementP(); // w:p + } + + /** + * Write textinput + * + * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html + */ + private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) + { + $default = $element->getDefault(); + + $xmlWriter->startElement('w:textInput'); + $xmlWriter->writeElementBlock('w:default', 'w:val', $default); + $xmlWriter->endElement(); + } + + /** + * Write checkbox + * + * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html + */ + private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) + { + $default = $element->getDefault() ? 1 : 0; + $value = $element->getValue(); + if ($value == null) { + $value = $default; + } + $value = $value ? 1 : 0; + + $xmlWriter->startElement('w:checkBox'); + $xmlWriter->writeElementBlock('w:sizeAuto', 'w:val', ''); + $xmlWriter->writeElementBlock('w:default', 'w:val', $default); + $xmlWriter->writeElementBlock('w:checked', 'w:val', $value); + $xmlWriter->endElement(); + } + + /** + * Write dropdown + * + * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html + */ + private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element) + { + $default = $element->getDefault(); + $value = $element->getValue(); + if ($value == null) { + $value = $default; + } + $entries = $element->getEntries(); + + $xmlWriter->startElement('w:ddList'); + $xmlWriter->writeElementBlock('w:result', 'w:val', $value); + $xmlWriter->writeElementBlock('w:default', 'w:val', $default); + foreach ($entries as $entry) { + $xmlWriter->writeElementBlock('w:listEntry', 'w:val', $entry); + } + $xmlWriter->endElement(); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 528cafd5..6c10f3a5 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -152,11 +152,11 @@ class ElementTest extends \PHPUnit_Framework_TestCase /** * Test shape elements */ - public function testChartElement() + public function testChartElements() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $style = array('width' => 1000000, 'height' => 1000000, '3d' => true); + $style = array('width' => 1000000, 'height' => 1000000); $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); $categories = array('A', 'B', 'C', 'D', 'E'); @@ -164,6 +164,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase foreach ($chartTypes as $chartType) { $section->addChart($chartType, $categories, $series1, $style); } + $section->addChart('pie', $categories, $series1, array('3d' => true)); $doc = TestHelperDOCX::getDocument($phpWord); @@ -175,4 +176,24 @@ class ElementTest extends \PHPUnit_Framework_TestCase $this->assertTrue($doc->elementExists($path, $file)); } } + + /** + * Test form fields + */ + public function testFormFieldElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $section->addFormField('textinput')->setName('MyTextBox'); + $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); + $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = "/w:document/w:body/w:p/w:r/w:fldChar/w:ffData"; + $this->assertTrue($doc->elementExists($path . '/w:textInput')); + $this->assertTrue($doc->elementExists($path . '/w:checkBox')); + $this->assertTrue($doc->elementExists($path . '/w:ddList')); + } } From 384107e7cfd87bc8a01c129c644bdeead6df192b Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 16 Jun 2014 07:32:57 +0700 Subject: [PATCH 269/326] Ability to define document protection and new `Metadata` subnamespace --- CHANGELOG.md | 3 +- README.md | 13 +- docs/general.rst | 8 +- docs/src/documentation.md | 6 +- samples/Sample_33_FormField.php | 1 + samples/Sample_Header.php | 2 +- samples/index.php | 2 +- .../DocInfo.php} | 8 +- src/PhpWord/Metadata/Protection.php | 69 +++++++++ src/PhpWord/PhpWord.php | 68 ++++++--- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- .../Reader/Word2007/DocPropsCustom.php | 8 +- src/PhpWord/Writer/HTML/Part/Head.php | 2 +- src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- src/PhpWord/Writer/PDF/MPDF.php | 2 +- src/PhpWord/Writer/PDF/TCPDF.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 +- .../Writer/Word2007/Part/DocPropsApp.php | 4 +- .../Writer/Word2007/Part/DocPropsCore.php | 18 +-- .../Writer/Word2007/Part/DocPropsCustom.php | 2 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 133 +++++++++++------- .../DocInfoTest.php} | 96 ++++++------- tests/PhpWord/Tests/PhpWordTest.php | 17 +-- tests/PhpWord/Tests/Writer/HTMLTest.php | 2 +- .../Tests/Writer/ODText/Part/ContentTest.php | 2 +- .../Writer/Word2007/Part/SettingsTest.php | 52 +++++++ 27 files changed, 357 insertions(+), 171 deletions(-) rename src/PhpWord/{DocumentProperties.php => Metadata/DocInfo.php} (99%) create mode 100644 src/PhpWord/Metadata/Protection.php rename tests/PhpWord/Tests/{DocumentPropertiesTest.php => Metadata/DocInfoTest.php} (67%) create mode 100644 tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 49fe9993..4775b4dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 - Chart: 3D charts and ability to set width and height - @ivanlanin - FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin GH-266 +- Security: Ability to define document protection (readOnly, comments, trackedChanges, forms) - @ivanlanin ### Bugfixes @@ -30,7 +31,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - `Element\Link::getTarget()` replaced by `Element\Link::getSource()` - `Element\Section::getSettings()` and `Element\Section::setSettings()` replaced by `Element\Section::getStyle()` and `Element\Section::setStyle()` - `Shared\Drawing` and `Shared\Font` merged into `Shared\Converter` - +- `DocumentProperties` replaced by `Metadata\DocInfo` ### Miscellaneous diff --git a/README.md b/README.md index 825f7926..841ab1a1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,17 @@ PHPWord is a library written in pure PHP that provides a set of classes to write PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/). +Read more about PHPWord: + +- [Features](#features) +- [Requirements](#requirements) +- [Installation](#installation) +- [Getting started](#getting-started) +- [Known issues](#known-issues) +- [Contributing](#contributing) +- [Developers' Documentation](http://phpword.readthedocs.org/) +- [API Documentation](http://phpoffice.github.io/PHPWord/docs/master/) + ## Features With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your PHP 5.3+ scripts. Below are some of the things that you can do with PHPWord library: @@ -113,7 +124,7 @@ $phpWord->save('helloWorld.odt', 'ODText'); $phpWord->save('helloWorld.rtf', 'RTF'); ``` -More examples are provided in the [samples folder](samples/). You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/) for more detail. +More examples are provided in the [samples folder](samples/). You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/master/) for more detail. ## Known issues diff --git a/docs/general.rst b/docs/general.rst index a2498aff..c6a893bc 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -97,15 +97,15 @@ default font by using the following two functions: $phpWord->setDefaultFontName('Times New Roman'); $phpWord->setDefaultFontSize(12); -Document properties -------------------- +Document information +-------------------- -You can set the document properties such as title, creator, and company +You can set the document information such as title, creator, and company name. Use the following functions: .. code-block:: php - $properties = $phpWord->getDocumentProperties(); + $properties = $phpWord->getDocInfo(); $properties->setCreator('My name'); $properties->setCompany('My factory'); $properties->setTitle('My title'); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 20996808..60121d33 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -279,12 +279,12 @@ $phpWord->setDefaultFontName('Times New Roman'); $phpWord->setDefaultFontSize(12); ``` -## Document properties +## Document information -You can set the document properties such as title, creator, and company name. Use the following functions: +You can set the document information such as title, creator, and company name. Use the following functions: ```php -$properties = $phpWord->getDocumentProperties(); +$properties = $phpWord->getDocInfo(); $properties->setCreator('My name'); $properties->setCompany('My factory'); $properties->setTitle('My title'); diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php index f7b7c852..d3811fc4 100644 --- a/samples/Sample_33_FormField.php +++ b/samples/Sample_33_FormField.php @@ -4,6 +4,7 @@ include_once 'Sample_Header.php'; // New Word document echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord->getProtection()->setEditing('forms'); $section = $phpWord->addSection(); diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index d915c039..838784c2 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -142,7 +142,7 @@ function getEndingNotes($writers) diff --git a/samples/index.php b/samples/index.php index 8e466d97..5632664f 100644 --- a/samples/index.php +++ b/samples/index.php @@ -16,7 +16,7 @@ if (!CLI) {

     

    Fork us on Github! - Read the Docs + Read the Docs

    setEditing($editing); + } + + /** + * Get editing protection + * + * @return string + */ + public function getEditing() + { + return $this->editing; + } + + /** + * Set editing protection + * + * @param string $editing + * @return self + */ + public function setEditing($editing = null) + { + $this->editing = $editing; + + return $this; + } +} diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index d4c8df9c..c62da82b 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -52,13 +52,6 @@ class PhpWord const DEFAULT_FONT_COLOR = Settings::DEFAULT_FONT_COLOR; const DEFAULT_FONT_CONTENT_TYPE = Settings::DEFAULT_FONT_CONTENT_TYPE; - /** - * Document properties object - * - * @var DocumentProperties - */ - private $documentProperties; - /** * Collection of sections * @@ -73,6 +66,14 @@ class PhpWord */ private $collections = array(); + /** + * Metadata + * + * @var array + * @since 0.12.0 + */ + private $metadata = array(); + /** * Create new instance * @@ -80,13 +81,17 @@ class PhpWord */ public function __construct() { - $this->documentProperties = new DocumentProperties(); - $collections = array('Titles', 'Footnotes', 'Endnotes', 'Charts'); foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); } + + $metadata = 'PhpOffice\\PhpWord\\Metadata\\Protection'; + $this->metadata['Protection'] = new $metadata(); + + $metadata = 'PhpOffice\\PhpWord\\Metadata\\DocInfo'; + $this->metadata['DocInfo'] = new $metadata(); } /** @@ -150,24 +155,22 @@ class PhpWord /** * Get document properties object * - * @return DocumentProperties + * @return \PhpOffice\PhpWord\Metadata\DocInfo */ - public function getDocumentProperties() + public function getDocInfo() { - return $this->documentProperties; + return $this->metadata['DocInfo']; } /** - * Set document properties object + * Get protection * - * @param DocumentProperties $documentProperties - * @return self + * @return \PhpOffice\PhpWord\Metadata\Protection + * @since 0.12.0 */ - public function setDocumentProperties(DocumentProperties $documentProperties) + public function getProtection() { - $this->documentProperties = $documentProperties; - - return $this; + return $this->metadata['Protection']; } /** @@ -312,4 +315,31 @@ class PhpWord { return $this->addSection($settings); } + + /** + * Get document properties object + * + * @return \PhpOffice\PhpWord\Metadata\DocInfo + * @deprecated 0.12.0 + * @codeCoverageIgnore + */ + public function getDocumentProperties() + { + return $this->getDocInfo(); + } + + /** + * Set document properties object + * + * @param \PhpOffice\PhpWord\Metadata\DocInfo + * @return self + * @deprecated 0.12.0 + * @codeCoverageIgnore + */ + public function setDocumentProperties($documentProperties) + { + $this->metadata['Document'] = $documentProperties; + + return $this; + } } diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index f7f4542d..518884fd 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -37,7 +37,7 @@ class Meta extends AbstractPart { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $metaNode = $xmlReader->getElement('office:meta'); diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 0b92b64d..e50f295b 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -61,7 +61,7 @@ class DocPropsCore extends AbstractPart $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index efbbfaa5..54fe39ee 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\PhpWord\DocumentProperties; +use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; @@ -37,7 +37,7 @@ class DocPropsCustom extends AbstractPart { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { @@ -46,8 +46,8 @@ class DocPropsCustom extends AbstractPart $attributeNode = $xmlReader->getElement('*', $node); $attributeType = $attributeNode->nodeName; $attributeValue = $attributeNode->nodeValue; - $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); - $attributeType = DocumentProperties::convertPropertyType($attributeType); + $attributeValue = DocInfo::convertProperty($attributeValue, $attributeType); + $attributeType = DocInfo::convertPropertyType($attributeType); $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); } } diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index edbc8dcf..23e30b8d 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -39,7 +39,7 @@ class Head extends AbstractPart */ public function write() { - $docProps = $this->getParentWriter()->getPhpWord()->getDocumentProperties(); + $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo(); $propertiesMapping = array( 'creator' => 'author', 'title' => '', diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index c9e729ad..9dab2e23 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -34,7 +34,7 @@ class Meta extends AbstractPart public function write() { $phpWord = $this->getParentWriter()->getPhpWord(); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $xmlWriter = $this->getXmlWriter(); $xmlWriter->startDocument('1.0', 'UTF-8'); diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 9d4e050c..3fab05c3 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -54,7 +54,7 @@ class MPDF extends AbstractRenderer implements WriterInterface // Write document properties $phpWord = $this->getPhpWord(); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $pdf->setTitle($docProps->getTitle()); $pdf->setAuthor($docProps->getCreator()); $pdf->setSubject($docProps->getSubject()); diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 669a2cdd..3d3104de 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -58,7 +58,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface // Write document properties $phpWord = $this->getPhpWord(); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $pdf->setTitle($docProps->getTitle()); $pdf->setAuthor($docProps->getCreator()); $pdf->setSubject($docProps->getSubject()); diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index f0a9b8f2..f239f9e2 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -52,7 +52,7 @@ class Document extends AbstractPart */ private function writeInfo() { - $docProps = $this->getParentWriter()->getPhpWord()->getDocumentProperties(); + $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo(); $properties = array('title', 'subject', 'category', 'keywords', 'comment', 'author', 'operator', 'creatim', 'revtim', 'company', 'manager'); $mapping = array('comment' => 'description', 'author' => 'creator', 'operator' => 'lastModifiedBy', diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index 1e6549c5..421ceefe 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -41,8 +41,8 @@ class DocPropsApp extends AbstractPart $xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); $xmlWriter->writeElement('Application', 'PHPWord'); - $xmlWriter->writeElement('Company', $phpWord->getDocumentProperties()->getCompany()); - $xmlWriter->writeElement('Manager', $phpWord->getDocumentProperties()->getManager()); + $xmlWriter->writeElement('Company', $phpWord->getDocInfo()->getCompany()); + $xmlWriter->writeElement('Manager', $phpWord->getDocInfo()->getManager()); $xmlWriter->endElement(); // Properties diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 38f6d235..252be01f 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -43,24 +43,24 @@ class DocPropsCore extends AbstractPart $xmlWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/'); $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); - $xmlWriter->writeElement('dc:creator', $phpWord->getDocumentProperties()->getCreator()); - $xmlWriter->writeElement('dc:title', $phpWord->getDocumentProperties()->getTitle()); - $xmlWriter->writeElement('dc:description', $phpWord->getDocumentProperties()->getDescription()); - $xmlWriter->writeElement('dc:subject', $phpWord->getDocumentProperties()->getSubject()); - $xmlWriter->writeElement('cp:keywords', $phpWord->getDocumentProperties()->getKeywords()); - $xmlWriter->writeElement('cp:category', $phpWord->getDocumentProperties()->getCategory()); - $xmlWriter->writeElement('cp:lastModifiedBy', $phpWord->getDocumentProperties()->getLastModifiedBy()); + $xmlWriter->writeElement('dc:creator', $phpWord->getDocInfo()->getCreator()); + $xmlWriter->writeElement('dc:title', $phpWord->getDocInfo()->getTitle()); + $xmlWriter->writeElement('dc:description', $phpWord->getDocInfo()->getDescription()); + $xmlWriter->writeElement('dc:subject', $phpWord->getDocInfo()->getSubject()); + $xmlWriter->writeElement('cp:keywords', $phpWord->getDocInfo()->getKeywords()); + $xmlWriter->writeElement('cp:category', $phpWord->getDocInfo()->getCategory()); + $xmlWriter->writeElement('cp:lastModifiedBy', $phpWord->getDocInfo()->getLastModifiedBy()); // dcterms:created $xmlWriter->startElement('dcterms:created'); $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $xmlWriter->writeRaw(date($this->dateFormat, $phpWord->getDocumentProperties()->getCreated())); + $xmlWriter->writeRaw(date($this->dateFormat, $phpWord->getDocInfo()->getCreated())); $xmlWriter->endElement(); // dcterms:modified $xmlWriter->startElement('dcterms:modified'); $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $xmlWriter->writeRaw(date($this->dateFormat, $phpWord->getDocumentProperties()->getModified())); + $xmlWriter->writeRaw(date($this->dateFormat, $phpWord->getDocInfo()->getModified())); $xmlWriter->endElement(); $xmlWriter->endElement(); // cp:coreProperties diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index c5a3cf9e..ba6547d9 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -39,7 +39,7 @@ class DocPropsCustom extends AbstractPart $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/custom-properties'); $xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $properties = $docProps->getCustomProperties(); foreach ($properties as $key => $property) { $propertyValue = $docProps->getCustomPropertyValue($property); diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d8535d8c..ac67b25d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -31,8 +31,91 @@ class Settings extends AbstractPart */ public function write() { - $settings = array( + $settings = $this->getSettings(); + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:settings'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:sl', 'http://schemas.openxmlformats.org/schemaLibrary/2006/main'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + + foreach ($settings as $settingKey => $settingValue) { + $this->writeSetting($xmlWriter, $settingKey, $settingValue); + } + + $xmlWriter->endElement(); // w:settings + + return $xmlWriter->getData(); + } + + /** + * Write indivual setting, recursive to any child settings + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $settingKey + * @param array|string $settingValue + */ + protected function writeSetting($xmlWriter, $settingKey, $settingValue) + { + if ($settingValue == '') { + $xmlWriter->writeElement($settingKey); + } else { + $xmlWriter->startElement($settingKey); + + /** @var array $settingValue Type hint */ + foreach ($settingValue as $childKey => $childValue) { + if ($childKey == '@attributes') { + foreach ($childValue as $key => $val) { + $xmlWriter->writeAttribute($key, $val); + } + } else { + $this->writeSetting($xmlWriter, $childKey, $childValue); + } + } + $xmlWriter->endElement(); + } + } + + /** + * Get settings + * + * @return array + */ + private function getSettings() + { + // Default settings + $settings = $this->getDefaultSettings(); + + // Protection + $protection = $this->getParentWriter()->getPhpWord()->getProtection(); + if ($protection->getEditing() !== null) { + $settings['w:documentProtection'] = array( + '@attributes' => array( + 'w:enforcement' => 1, + 'w:edit' => $protection->getEditing(), + ) + ); + } + + return $settings; + } + + /** + * Get default settings + * + * @return array + */ + private function getDefaultSettings() + { + return array( 'w:zoom' => array('@attributes' => array('w:percent' => '100')), + 'w:view' => array('@attributes' => array('w:val' => 'print')), 'w:embedSystemFonts' => '', 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), @@ -94,53 +177,5 @@ class Settings extends AbstractPart 'w:decimalSymbol' => array('@attributes' => array('w:val' => ',')), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), ); - - $xmlWriter = $this->getXmlWriter(); - - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('w:settings'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); - $xmlWriter->writeAttribute('xmlns:sl', 'http://schemas.openxmlformats.org/schemaLibrary/2006/main'); - $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); - $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); - $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); - - foreach ($settings as $settingKey => $settingValue) { - $this->writeSetting($xmlWriter, $settingKey, $settingValue); - } - - $xmlWriter->endElement(); // w:settings - - return $xmlWriter->getData(); - } - - /** - * Write indivual setting, recursive to any child settings - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param string $settingKey - * @param array|string $settingValue - */ - protected function writeSetting($xmlWriter, $settingKey, $settingValue) - { - if ($settingValue == '') { - $xmlWriter->writeElement($settingKey); - } else { - $xmlWriter->startElement($settingKey); - - /** @var array $settingValue Type hint */ - foreach ($settingValue as $childKey => $childValue) { - if ($childKey == '@attributes') { - foreach ($childValue as $key => $val) { - $xmlWriter->writeAttribute($key, $val); - } - } else { - $this->writeSetting($xmlWriter, $childKey, $childValue); - } - } - $xmlWriter->endElement(); - } } } diff --git a/tests/PhpWord/Tests/DocumentPropertiesTest.php b/tests/PhpWord/Tests/Metadata/DocInfoTest.php similarity index 67% rename from tests/PhpWord/Tests/DocumentPropertiesTest.php rename to tests/PhpWord/Tests/Metadata/DocInfoTest.php index 30b2a7bc..c860a0d9 100644 --- a/tests/PhpWord/Tests/DocumentPropertiesTest.php +++ b/tests/PhpWord/Tests/Metadata/DocInfoTest.php @@ -15,23 +15,23 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord\Tests\Metadata; -use PhpOffice\PhpWord\DocumentProperties; +use PhpOffice\PhpWord\Metadata\DocInfo; /** - * Test class for PhpOffice\PhpWord\DocumentProperties + * Test class for PhpOffice\PhpWord\Metadata\DocInfo * * @runTestsInSeparateProcesses */ -class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase +class DocInfoTest extends \PHPUnit_Framework_TestCase { /** * Creator */ public function testCreator() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setCreator(); $this->assertEquals('', $oProperties->getCreator()); @@ -44,7 +44,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testLastModifiedBy() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setLastModifiedBy(); $this->assertEquals('', $oProperties->getLastModifiedBy()); @@ -57,7 +57,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testCreated() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setCreated(); $this->assertEquals(time(), $oProperties->getCreated()); @@ -71,7 +71,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testModified() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setModified(); $this->assertEquals(time(), $oProperties->getModified()); @@ -85,7 +85,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testTitle() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setTitle(); $this->assertEquals('', $oProperties->getTitle()); @@ -98,7 +98,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testDescription() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setDescription(); $this->assertEquals('', $oProperties->getDescription()); @@ -111,7 +111,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testSubject() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setSubject(); $this->assertEquals('', $oProperties->getSubject()); @@ -124,7 +124,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testKeywords() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setKeywords(); $this->assertEquals('', $oProperties->getKeywords()); @@ -137,7 +137,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testCategory() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setCategory(); $this->assertEquals('', $oProperties->getCategory()); @@ -150,7 +150,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testCompany() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setCompany(); $this->assertEquals('', $oProperties->getCompany()); @@ -163,7 +163,7 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testManager() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setManager(); $this->assertEquals('', $oProperties->getManager()); @@ -176,30 +176,30 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testCustomProperty() { - $oProperties = new DocumentProperties(); + $oProperties = new DocInfo(); $oProperties->setCustomProperty('key1', null); $oProperties->setCustomProperty('key2', true); $oProperties->setCustomProperty('key3', 3); $oProperties->setCustomProperty('key4', 4.4); $oProperties->setCustomProperty('key5', 'value5'); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_STRING, + DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key1') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_BOOLEAN, + DocInfo::PROPERTY_TYPE_BOOLEAN, $oProperties->getCustomPropertyType('key2') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_INTEGER, + DocInfo::PROPERTY_TYPE_INTEGER, $oProperties->getCustomPropertyType('key3') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_FLOAT, + DocInfo::PROPERTY_TYPE_FLOAT, $oProperties->getCustomPropertyType('key4') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_STRING, + DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key5') ); $this->assertEquals(null, $oProperties->getCustomPropertyType('key6')); @@ -225,50 +225,50 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase */ public function testConvertProperty() { - $this->assertEquals('', DocumentProperties::convertProperty('a', 'empty')); - $this->assertEquals(null, DocumentProperties::convertProperty('a', 'null')); - $this->assertEquals(8, DocumentProperties::convertProperty('8', 'int')); - $this->assertEquals(8, DocumentProperties::convertProperty('8.3', 'uint')); - $this->assertEquals(8.3, DocumentProperties::convertProperty('8.3', 'decimal')); - $this->assertEquals('8.3', DocumentProperties::convertProperty('8.3', 'lpstr')); - $this->assertEquals(strtotime('10/11/2013'), DocumentProperties::convertProperty('10/11/2013', 'date')); - $this->assertEquals(true, DocumentProperties::convertProperty('true', 'bool')); - $this->assertEquals(false, DocumentProperties::convertProperty('1', 'bool')); - $this->assertEquals('1', DocumentProperties::convertProperty('1', 'array')); - $this->assertEquals('1', DocumentProperties::convertProperty('1', '')); + $this->assertEquals('', DocInfo::convertProperty('a', 'empty')); + $this->assertEquals(null, DocInfo::convertProperty('a', 'null')); + $this->assertEquals(8, DocInfo::convertProperty('8', 'int')); + $this->assertEquals(8, DocInfo::convertProperty('8.3', 'uint')); + $this->assertEquals(8.3, DocInfo::convertProperty('8.3', 'decimal')); + $this->assertEquals('8.3', DocInfo::convertProperty('8.3', 'lpstr')); + $this->assertEquals(strtotime('10/11/2013'), DocInfo::convertProperty('10/11/2013', 'date')); + $this->assertEquals(true, DocInfo::convertProperty('true', 'bool')); + $this->assertEquals(false, DocInfo::convertProperty('1', 'bool')); + $this->assertEquals('1', DocInfo::convertProperty('1', 'array')); + $this->assertEquals('1', DocInfo::convertProperty('1', '')); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_INTEGER, - DocumentProperties::convertPropertyType('int') + DocInfo::PROPERTY_TYPE_INTEGER, + DocInfo::convertPropertyType('int') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_INTEGER, - DocumentProperties::convertPropertyType('uint') + DocInfo::PROPERTY_TYPE_INTEGER, + DocInfo::convertPropertyType('uint') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_FLOAT, - DocumentProperties::convertPropertyType('decimal') + DocInfo::PROPERTY_TYPE_FLOAT, + DocInfo::convertPropertyType('decimal') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_STRING, - DocumentProperties::convertPropertyType('lpstr') + DocInfo::PROPERTY_TYPE_STRING, + DocInfo::convertPropertyType('lpstr') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_DATE, - DocumentProperties::convertPropertyType('date') + DocInfo::PROPERTY_TYPE_DATE, + DocInfo::convertPropertyType('date') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_BOOLEAN, - DocumentProperties::convertPropertyType('bool') + DocInfo::PROPERTY_TYPE_BOOLEAN, + DocInfo::convertPropertyType('bool') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_UNKNOWN, - DocumentProperties::convertPropertyType('array') + DocInfo::PROPERTY_TYPE_UNKNOWN, + DocInfo::convertPropertyType('array') ); $this->assertEquals( - DocumentProperties::PROPERTY_TYPE_UNKNOWN, - DocumentProperties::convertPropertyType('') + DocInfo::PROPERTY_TYPE_UNKNOWN, + DocInfo::convertPropertyType('') ); } } diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index ca49bf28..6fd4b291 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests; -use PhpOffice\PhpWord\DocumentProperties; +use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; @@ -35,24 +35,11 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase public function testConstruct() { $phpWord = new PhpWord(); - $this->assertEquals(new DocumentProperties(), $phpWord->getDocumentProperties()); + $this->assertEquals(new DocInfo(), $phpWord->getDocInfo()); $this->assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); $this->assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); } - /** - * Test set/get document properties - */ - public function testSetGetDocumentProperties() - { - $phpWord = new PhpWord(); - $creator = 'PhpWord'; - $properties = $phpWord->getDocumentProperties(); - $properties->setCreator($creator); - $phpWord->setDocumentProperties($properties); - $this->assertEquals($creator, $phpWord->getDocumentProperties()->getCreator()); - } - /** * Test create/get section */ diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index f9b8e6ba..c3339d1a 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -61,7 +61,7 @@ class HTMLTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $docProps->setTitle('HTML Test'); $phpWord->addTitleStyle(1, array('bold' => true)); diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index 27b2427f..85ddada6 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -47,7 +47,7 @@ class ContentTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); - $docProps = $phpWord->getDocumentProperties(); + $docProps = $phpWord->getDocInfo(); $docProps->setCustomProperty('Company', 'PHPWord'); $phpWord->setDefaultFontName('Verdana'); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php new file mode 100644 index 00000000..de78c34a --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php @@ -0,0 +1,52 @@ +getProtection()->setEditing('forms'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:documentProtection'; + $this->assertTrue($doc->elementExists($path, $file)); + } +} From 5c8e100d4113641e93e1f150c0c84c2e15aeb3c6 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 16 Jun 2014 16:23:41 +0700 Subject: [PATCH 270/326] Bugfix #280: Table inside vertical border does not rendered properly --- CHANGELOG.md | 1 + src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4775b4dc..40805cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo GH-261 - `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich GH-270 - Page breaks on titles and tables - @ivanlanin GH-274 +- Table inside vertical border does not rendered properly - @ivanlanin GH-280 ### Deprecated diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 88bb0109..38dff148 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -55,7 +55,7 @@ class MarginBorder extends AbstractStyle $xmlWriter = $this->getXmlWriter(); $sides = array('top', 'left', 'right', 'bottom', 'insideH', 'insideV'); - $sizeCount = count($this->sizes) - 1; + $sizeCount = count($this->sizes); for ($i = 0; $i < $sizeCount; $i++) { if ($this->sizes[$i] !== null) { From 71b4ac9c56f87763011e480257874103ea16bbf6 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 17 Jun 2014 15:48:39 +0200 Subject: [PATCH 271/326] FIXED : #282 : problem converting docx to pdf PHP Catchable fatal error: Argument 2 passed to DOMXPath::query() must be an instance of DOMNode, null given, called in /var/www/xxx/PhpWord/Reader/Word2007.php on line 145 and defined in /var/www/xxx/PhpWord/Shared/XMLReader.php on line 99, referer: XXX --- src/PhpWord/Shared/XMLReader.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 153152ee..ca6869eb 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -96,7 +96,11 @@ class XMLReader $this->xpath = new \DOMXpath($this->dom); } - return $this->xpath->query($path, $contextNode); + if (is_null($contextNode)) { + return $this->xpath->query($path); + } else { + return $this->xpath->query($path, $contextNode); + } } /** From f19353405815589dd1dc055b7355774371e8f98a Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 17 Jun 2014 16:08:28 +0200 Subject: [PATCH 272/326] FIXED : CI : Error with the generation of the PHPDoc Deprecated: phpDocumentor2 should be run from the phpdoc file, not phpdoc.php in /home/travis/build/PHPOffice/PHPWord/vendor/phpdocumentor/phpdocumentor/bin/phpdoc.php on line 13 Refs : https://github.com/phpDocumentor/phpDocumentor2/blob/395af1d42a3fe8af7eedeea28e530ab2fdd2bd06/bin/phpdoc.php --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 73dd68ec..dfee2bb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ script: ## PHPUnit - phpunit -c ./ --coverage-text --coverage-html ./build/coverage ## PHPDocumentor - - vendor/bin/phpdoc.php -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" + - vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" after_script: ## PHPDocumentor From eeca39670469f60110e6601714c240fb18b0ccad Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 19 Jun 2014 11:59:57 +0400 Subject: [PATCH 273/326] [CHANGED] Added annotations to StyleTest and performed minor refactoring. --- tests/PhpWord/Tests/StyleTest.php | 36 +++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index f446ecdf..ef6c665c 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -22,43 +22,61 @@ use PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style * + * @coversDefaultClass \PhpOffice\PhpWord\Style * @runTestsInSeparateProcesses */ class StyleTest extends \PHPUnit_Framework_TestCase { /** * Add and get paragraph, font, link, title, and table styles + * + * @covers ::addParagraphStyle + * @covers ::addFontStyle + * @covers ::addLinkStyle + * @covers ::addTitleStyle + * @covers ::addTableStyle + * @covers ::setDefaultParagraphStyle + * @covers ::countStyles + * @covers ::getStyle + * @covers ::resetStyles + * @covers ::getStyles + * @test */ public function testStyles() { $paragraph = array('align' => 'center'); $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); - $styles = array('Paragraph' => 'Paragraph', 'Font' => 'Font', - 'Link' => 'Font', 'Table' => 'Table', - 'Heading_1' => 'Font', 'Normal' => 'Paragraph'); - $elementCount = 6; + $styles = array( + 'Paragraph' => 'Paragraph', + 'Font' => 'Font', + 'Link' => 'Font', + 'Table' => 'Table', + 'Heading_1' => 'Font', + 'Normal' => 'Paragraph' + ); Style::addParagraphStyle('Paragraph', $paragraph); Style::addFontStyle('Font', $font); Style::addLinkStyle('Link', $font); - Style::addTableStyle('Table', $table); + // @todo Style::addNumberingStyle Style::addTitleStyle(1, $font); + Style::addTableStyle('Table', $table); Style::setDefaultParagraphStyle($paragraph); - $this->assertEquals($elementCount, count(Style::getStyles())); + $this->assertEquals(count($styles), Style::countStyles()); foreach ($styles as $name => $style) { $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$style}", Style::getStyle($name)); } $this->assertNull(Style::getStyle('Unknown')); Style::resetStyles(); - $this->assertEquals(0, count(Style::getStyles())); - + $this->assertCount(0, Style::getStyles()); } /** - * Set default paragraph style + * @covers ::setDefaultParagraphStyle + * @test */ public function testDefaultParagraphStyle() { From c11df2e4263cbf394c8c6f51651d76944f8c3d71 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 19 Jun 2014 12:04:07 +0400 Subject: [PATCH 274/326] [CHANGED] Added annotations to StyleTest and performed minor refactoring. --- tests/PhpWord/Tests/StyleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index ef6c665c..a8890b96 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -53,7 +53,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase 'Link' => 'Font', 'Table' => 'Table', 'Heading_1' => 'Font', - 'Normal' => 'Paragraph' + 'Normal' => 'Paragraph', ); Style::addParagraphStyle('Paragraph', $paragraph); From d35db836dc59b096d14cc06e33a395a847a18586 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 20 Jun 2014 09:00:12 +0400 Subject: [PATCH 275/326] [CHANGED] Added annotations to StyleTest and performed minor refactoring. --- tests/PhpWord/Tests/StyleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index a8890b96..23af4b2e 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -64,7 +64,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase Style::addTableStyle('Table', $table); Style::setDefaultParagraphStyle($paragraph); - $this->assertEquals(count($styles), Style::countStyles()); + $this->assertCount(count($styles), Style::getStyles()); foreach ($styles as $name => $style) { $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$style}", Style::getStyle($name)); } From 0ea21939067effbc80e8b7125db586afda173323 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 20 Jun 2014 09:34:49 +0400 Subject: [PATCH 276/326] [CHANGED] Replaced "assertEquals" with "assertCount" where it was necessary. --- tests/PhpWord/Tests/AutoloaderTest.php | 7 +++---- tests/PhpWord/Tests/Collection/CollectionTest.php | 3 +-- tests/PhpWord/Tests/MediaTest.php | 14 ++++++-------- tests/PhpWord/Tests/PhpWordTest.php | 2 +- tests/PhpWord/Tests/Shared/HtmlTest.php | 4 ++-- tests/PhpWord/Tests/Style/ParagraphTest.php | 2 +- 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index 92423fc6..dace5bdb 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -43,12 +43,11 @@ class AutoloaderTest extends \PHPUnit_Framework_TestCase */ public function testAutoload() { - $declared = get_declared_classes(); - $declaredCount = count($declared); + $declaredCount = count(get_declared_classes()); Autoloader::autoload('Foo'); - $this->assertEquals( + $this->assertCount( $declaredCount, - count(get_declared_classes()), + get_declared_classes(), 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' . 'classes outside of the PhpOffice\\PhpWord namespace' ); diff --git a/tests/PhpWord/Tests/Collection/CollectionTest.php b/tests/PhpWord/Tests/Collection/CollectionTest.php index e3d08da2..833b3e80 100644 --- a/tests/PhpWord/Tests/Collection/CollectionTest.php +++ b/tests/PhpWord/Tests/Collection/CollectionTest.php @@ -28,8 +28,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase $object->addItem(new Footnote()); // addItem #1 $this->assertEquals(2, $object->addItem(new Footnote())); // addItem #2. Should returns new item index - $this->assertEquals(2, $object->countItems()); // There are two items now - $this->assertEquals(2, count($object->getItems())); // getItems returns array + $this->assertCount(2, $object->getItems()); // getItems returns array $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $object->getItem(1)); // getItem returns object $this->assertNull($object->getItem(3)); // getItem returns null when invalid index is referenced diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 1b89b7c1..0196a7e1 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -40,7 +40,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testCountSectionMediaElementsWithNull() { - $this->assertEquals(Media::countElements('section'), 0); + $this->assertEquals(0, Media::countElements('section')); } /** @@ -57,7 +57,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase Media::addElement('section', 'object', $object); Media::addElement('section', 'object', $object); - $this->assertEquals(3, Media::countElements('section')); + $this->assertCount(3, Media::getElements('section')); } /** @@ -69,8 +69,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase $actual = Media::addElement('section', 'link', 'http://test.com'); $this->assertEquals($expected, $actual); - $this->assertEquals(1, Media::countElements('section', 'link')); - $this->assertEquals(1, count(Media::getElements('section', 'link'))); + $this->assertCount(1, Media::getElements('section', 'link')); } /** @@ -84,8 +83,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase Media::addElement('header1', 'image', $local, new Image($local)); Media::addElement('header1', 'image', $remote, new Image($remote)); - $this->assertEquals(2, Media::countElements('header1')); - $this->assertEquals(2, count(Media::getElements('header1'))); + $this->assertCount(2, Media::getElements('header1')); $this->assertEmpty(Media::getElements('header2')); } @@ -100,10 +98,10 @@ class MediaTest extends \PHPUnit_Framework_TestCase Media::addElement('footer1', 'image', $local, new Image($local)); Media::addElement('footer1', 'image', $remote, new Image($remote)); - $this->assertEquals(2, Media::countElements('footer1')); + $this->assertCount(2, Media::getElements('footer1')); Media::resetElements(); - $this->assertEquals(0, Media::countElements('footer1')); + $this->assertCount(0, Media::getElements('footer1')); } /** diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 6fd4b291..75b2d288 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -47,7 +47,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $phpWord->addSection(); - $this->assertEquals(1, count($phpWord->getSections())); + $this->assertCount(1, $phpWord->getSections()); } /** diff --git a/tests/PhpWord/Tests/Shared/HtmlTest.php b/tests/PhpWord/Tests/Shared/HtmlTest.php index e7b3533e..c4c0fc9d 100644 --- a/tests/PhpWord/Tests/Shared/HtmlTest.php +++ b/tests/PhpWord/Tests/Shared/HtmlTest.php @@ -34,7 +34,7 @@ class HtmlTest extends \PHPUnit_Framework_TestCase // Default $section = new Section(1); - $this->assertEquals(0, $section->countElements()); + $this->assertCount(0, $section->getElements()); // Heading $styles = array('strong', 'em', 'sup', 'sub'); @@ -52,7 +52,7 @@ class HtmlTest extends \PHPUnit_Framework_TestCase // Add HTML Html::addHtml($section, $content); - $this->assertEquals(7, $section->countElements()); + $this->assertCount(7, $section->getElements()); // Other parts $section = new Section(1); diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 12aa51ce..73540b0c 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -119,7 +119,7 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase { $object = new Paragraph(); $object->setTabs(array(new Tab('left', 1550), new Tab('right', 5300))); - $this->assertEquals(2, count($object->getTabs())); + $this->assertCount(2, $object->getTabs()); } /** From cd547927eaa6385cf1d2471d642e2d60677c193a Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 20 Jun 2014 22:24:59 +0700 Subject: [PATCH 277/326] New structured document tag (SDT) element --- samples/Sample_34_SDT.php | 17 +++ src/PhpWord/Element/AbstractContainer.php | 4 +- src/PhpWord/Element/SDT.php | 130 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/SDT.php | 71 ++++++++++ .../Tests/Writer/Word2007/ElementTest.php | 2 +- 5 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 samples/Sample_34_SDT.php create mode 100644 src/PhpWord/Element/SDT.php create mode 100644 src/PhpWord/Writer/Word2007/Element/SDT.php diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php new file mode 100644 index 00000000..fc1e7de6 --- /dev/null +++ b/samples/Sample_34_SDT.php @@ -0,0 +1,17 @@ +getProtection()->setEditing('forms'); + +$section = $phpWord->addSection(); + +$section->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 3ec11390..afde4270 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -43,6 +43,7 @@ namespace PhpOffice\PhpWord\Element; * @method Shape addObject(string $type, mixed $style = null) * @method Chart addChart(string $type, array $categories, array $values, array $style = null) * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) + * @method SDT addSDT(string $type) * * @since 0.10.0 */ @@ -79,7 +80,7 @@ abstract class AbstractContainer extends AbstractElement $elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', - 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField'); + 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField', 'SDT'); $functions = array(); for ($i = 0; $i < count($elements); $i++) { $functions[$i] = 'add' . $elements[$i]; @@ -205,6 +206,7 @@ abstract class AbstractContainer extends AbstractElement 'TOC' => array('Section'), 'PageBreak' => array('Section'), 'Chart' => array('Section'), + 'SDT' => array('Section'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php new file mode 100644 index 00000000..477c50f3 --- /dev/null +++ b/src/PhpWord/Element/SDT.php @@ -0,0 +1,130 @@ +setType($type); + } + + /** + * Get type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set type + * + * @param string $value + * @return self + */ + public function setType($value) + { + $enum = array('comboBox', 'dropDownList', 'date'); + $this->type = $this->setEnumVal($value, $enum, $this->type); + + return $this; + } + + /** + * Get value + * + * @return string|bool|int + */ + public function getValue() + { + return $this->value; + } + + /** + * Set value + * + * @param string|bool|int $value + * @return self + */ + public function setValue($value) + { + $this->value = $value; + + return $this; + } + + /** + * Get listItems + * + * @return array + */ + public function getListItems() + { + return $this->listItems; + } + + /** + * Set listItems + * + * @param array $value + * @return self + */ + public function setListItems($value) + { + $this->listItems = $value; + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php new file mode 100644 index 00000000..d25eaf98 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -0,0 +1,71 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof SDTElement) { + return; + } + $type = $element->getType(); + $listItems = $element->getListItems(); + + $this->startElementP(); + + $xmlWriter->startElement('w:sdt'); + + $xmlWriter->startElement('w:sdtPr'); + $xmlWriter->writeElementBlock('w:id', 'w:val', rand(100000000, 999999999)); + $xmlWriter->writeElementBlock('w:lock', 'w:val', 'sdtLocked'); + + $xmlWriter->startElement('w:placeholder'); + $xmlWriter->writeElementBlock('w:docPart', 'w:val', 'string'); + $xmlWriter->endElement(); // w:placeholder + + $xmlWriter->startElement("w:{$type}"); + foreach ($listItems as $key => $val) { + $xmlWriter->writeElementBlock('w:listItem', array('w:value' => $key, 'w:displayText' => $val)); + } + $xmlWriter->endElement(); // w:{$type} + + $xmlWriter->endElement(); // w:sdtPr + + $xmlWriter->startElement('w:sdtContent'); + $xmlWriter->endElement(); // w:sdtContent + + $xmlWriter->endElement(); // w:sdt + + $this->endElementP(); // w:p + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 6c10f3a5..752415a1 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -41,7 +41,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', - 'Field', 'Line', 'Shape', 'Chart' + 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT' ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; From 5be8414ef878372adb29c9b3ad1e8746e9a43334 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 21 Jun 2014 03:07:11 +0700 Subject: [PATCH 278/326] Settings: OOXML compatibility --- CHANGELOG.md | 3 +- docs/recipes.rst | 9 ++ docs/src/documentation.md | 8 ++ src/PhpWord/Metadata/Compatibility.php | 62 ++++++++++ src/PhpWord/PhpWord.php | 28 +++-- src/PhpWord/Writer/Word2007/Part/Settings.php | 106 ++++++++---------- tests/PhpWord/Tests/StyleTest.php | 2 + .../Writer/Word2007/Part/SettingsTest.php | 16 +++ 8 files changed, 167 insertions(+), 67 deletions(-) create mode 100644 src/PhpWord/Metadata/Compatibility.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 40805cb8..22f22dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 - Chart: 3D charts and ability to set width and height - @ivanlanin - FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin GH-266 -- Security: Ability to define document protection (readOnly, comments, trackedChanges, forms) - @ivanlanin +- Setting: Ability to define document protection (readOnly, comments, trackedChanges, forms) - @ivanlanin +- Setting: Ability to remove [Compatibility Mode] text in the MS Word title bar - @ivanlanin ### Bugfixes diff --git a/docs/recipes.rst b/docs/recipes.rst index 1b529d7b..0be6b4e0 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -87,3 +87,12 @@ Apply 'HeadingN' paragraph style to TextRun or Link. Sample code: // Link $section->addLink('https://github.com/', 'GitHub', 'Link', 'Heading2'); + +Remove [Compatibility Mode] text in the MS Word title bar +--------------------------------------------------------- + +Use the ``Metadata\Compatibility\setOoxmlVersion(n)`` method with ``n`` is the version of Office (14 = Office 2010, 15 = Office 2013). + +.. code-block:: php + + $phpWord->getCompatibility()->setOoxmlVersion(15); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 60121d33..9c0c865b 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -1053,6 +1053,14 @@ $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord', 'Link'); $section->addLink('https://github.com/', 'GitHub', 'Link', 'Heading2'); ``` +## Remove [Compatibility Mode] text in the MS Word title bar + +Use the `Metadata\Compatibility\setOoxmlVersion(n)` method with `n` is the version of Office (14 = Office 2010, 15 = Office 2013). + +```php +$phpWord->getCompatibility()->setOoxmlVersion(15); +``` + # Frequently asked questions ## Is this the same with PHPWord that I found in CodePlex? diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php new file mode 100644 index 00000000..d78b97f1 --- /dev/null +++ b/src/PhpWord/Metadata/Compatibility.php @@ -0,0 +1,62 @@ +ooxmlVersion; + } + + /** + * Set OOXML version + * + * @param int $value + * @return self + */ + public function setOoxmlVersion($value) + { + $this->ooxmlVersion = $value; + + return $this; + } +} diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index c62da82b..be808f01 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -81,17 +81,19 @@ class PhpWord */ public function __construct() { + // Collection $collections = array('Titles', 'Footnotes', 'Endnotes', 'Charts'); foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); } - $metadata = 'PhpOffice\\PhpWord\\Metadata\\Protection'; - $this->metadata['Protection'] = new $metadata(); - - $metadata = 'PhpOffice\\PhpWord\\Metadata\\DocInfo'; - $this->metadata['DocInfo'] = new $metadata(); + // Metadata + $metadata = array('DocInfo', 'Protection', 'Compatibility'); + foreach ($metadata as $meta) { + $class = 'PhpOffice\\PhpWord\\Metadata\\' . $meta; + $this->metadata[$meta] = new $class(); + } } /** @@ -147,9 +149,6 @@ class PhpWord if (in_array($function, $addStyle)) { return forward_static_call_array(array('PhpOffice\\PhpWord\\Style', $function), $args); } - - // All other methods - return null; } /** @@ -173,6 +172,17 @@ class PhpWord return $this->metadata['Protection']; } + /** + * Get compatibility + * + * @return \PhpOffice\PhpWord\Metadata\Compatibility + * @since 0.12.0 + */ + public function getCompatibility() + { + return $this->metadata['Compatibility']; + } + /** * Get all sections * @@ -331,7 +341,7 @@ class PhpWord /** * Set document properties object * - * @param \PhpOffice\PhpWord\Metadata\DocInfo + * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties * @return self * @deprecated 0.12.0 * @codeCoverageIgnore diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index ac67b25d..d381d26a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -24,6 +24,13 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; */ class Settings extends AbstractPart { + /** + * Settings value + * + * @var array + */ + private $settings = array(); + /** * Write part * @@ -31,7 +38,7 @@ class Settings extends AbstractPart */ public function write() { - $settings = $this->getSettings(); + $this->getSettings(); $xmlWriter = $this->getXmlWriter(); @@ -45,7 +52,7 @@ class Settings extends AbstractPart $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); - foreach ($settings as $settingKey => $settingValue) { + foreach ($this->settings as $settingKey => $settingValue) { $this->writeSetting($xmlWriter, $settingKey, $settingValue); } @@ -84,63 +91,19 @@ class Settings extends AbstractPart /** * Get settings - * - * @return array */ private function getSettings() { // Default settings - $settings = $this->getDefaultSettings(); - - // Protection - $protection = $this->getParentWriter()->getPhpWord()->getProtection(); - if ($protection->getEditing() !== null) { - $settings['w:documentProtection'] = array( - '@attributes' => array( - 'w:enforcement' => 1, - 'w:edit' => $protection->getEditing(), - ) - ); - } - - return $settings; - } - - /** - * Get default settings - * - * @return array - */ - private function getDefaultSettings() - { - return array( + $this->settings = array( 'w:zoom' => array('@attributes' => array('w:percent' => '100')), - 'w:view' => array('@attributes' => array('w:val' => 'print')), - 'w:embedSystemFonts' => '', 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), - 'w:doNotHyphenateCaps' => '', 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), - 'w:doNotValidateAgainstSchema' => '', - 'w:doNotDemarcateInvalidXml' => '', - 'w:compat' => array( - 'w:useNormalStyleForList' => '', - 'w:doNotUseIndentAsNumberingTabStop' => '', - 'w:useAltKinsokuLineBreakRules' => '', - 'w:allowSpaceOfSameStyleInTable' => '', - 'w:doNotSuppressIndentation' => '', - 'w:doNotAutofitConstrainedTables' => '', - 'w:autofitToFirstFixedWidthCell' => '', - 'w:underlineTabInNumList' => '', - 'w:displayHangulFixedWidth' => '', - // Commented for GH-274 - // 'w:splitPgBreakAndParaMark' => '', - 'w:doNotVertAlignCellWithSp' => '', - 'w:doNotBreakConstrainedForcedTable' => '', - 'w:doNotVertAlignInTxbx' => '', - 'w:useAnsiKerningPairs' => '', - 'w:cachedColBalance' => '', - ), + 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), + 'w:decimalSymbol' => array('@attributes' => array('w:val' => '.')), + 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), + 'w:compat' => '', 'm:mathPr' => array( 'm:mathFont' => array('@attributes' => array('m:val' => 'Cambria Math')), 'm:brkBin' => array('@attributes' => array('m:val' => 'before')), @@ -154,8 +117,6 @@ class Settings extends AbstractPart 'm:intLim' => array('@attributes' => array('m:val' => 'subSup')), 'm:naryLim' => array('@attributes' => array('m:val' => 'undOvr')), ), - 'w:uiCompat97To2003' => '', - 'w:themeFontLang' => array('@attributes' => array('w:val' => 'de-DE')), 'w:clrSchemeMapping' => array( '@attributes' => array( 'w:bg1' => 'light1', @@ -172,10 +133,41 @@ class Settings extends AbstractPart 'w:followedHyperlink' => 'followedHyperlink', ), ), - 'w:doNotIncludeSubdocsInStats' => '', - 'w:doNotAutoCompressPictures' => '', - 'w:decimalSymbol' => array('@attributes' => array('w:val' => ',')), - 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), ); + + // Other settings + $this->getProtection(); + $this->getCompatibility(); + } + + /** + * Get protection settings + */ + private function getProtection() + { + $protection = $this->getParentWriter()->getPhpWord()->getProtection(); + if ($protection->getEditing() !== null) { + $this->settings['w:documentProtection'] = array( + '@attributes' => array( + 'w:enforcement' => 1, + 'w:edit' => $protection->getEditing(), + ) + ); + } + } + + /** + * Get compatibility setting + */ + private function getCompatibility() + { + $compatibility = $this->getParentWriter()->getPhpWord()->getCompatibility(); + if ($compatibility->getOoxmlVersion() !== null) { + $this->settings['w:compat']['w:compatSetting'] = array('@attributes' => array( + 'w:name' => 'compatibilityMode', + 'w:uri' => 'http://schemas.microsoft.com/office/word', + 'w:val' => $compatibility->getOoxmlVersion(), + )); + } } } diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index 23af4b2e..6165e4fd 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -75,6 +75,8 @@ class StyleTest extends \PHPUnit_Framework_TestCase } /** + * Test default paragraph style + * * @covers ::setDefaultParagraphStyle * @test */ diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php index de78c34a..7d4d1849 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php @@ -49,4 +49,20 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $path = '/w:settings/w:documentProtection'; $this->assertTrue($doc->elementExists($path, $file)); } + + /** + * Test compatibility + */ + public function testCompatibility() + { + $phpWord = new PhpWord(); + $phpWord->getCompatibility()->setOoxmlVersion(15); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:compat/w:compatSetting'; + $this->assertTrue($doc->elementExists($path, $file)); + } } From 8efe80b5c106d87be68647bdfc2661342ebdacc3 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 22 Jun 2014 09:27:10 +0700 Subject: [PATCH 279/326] QA: Use Composer for Travis test tools --- .travis.yml | 23 +-- composer.json | 3 + composer.lock | 418 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 419 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index dfee2bb9..d92e23b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,17 +23,6 @@ before_script: ## Composer - composer self-update - composer install --prefer-source --dev - ## PHP Copy/Paste Detector - - curl -o phpcpd.phar https://phar.phpunit.de/phpcpd.phar - ## PHP Mess Detector - - pear config-set preferred_state beta - - printf "\n" | pecl install imagick - - pear channel-discover pear.phpmd.org - - pear channel-discover pear.pdepend.org - - pear install --alldeps phpmd/PHP_PMD - - phpenv rehash - ## PHPLOC - #- curl -o phploc.phar https://phar.phpunit.de/phploc.phar ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage @@ -42,15 +31,15 @@ script: ## PHP_CodeSniffer - ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ## PHP Copy/Paste Detector - - php phpcpd.phar src/ tests/ --verbose + - ./vendor/bin/phpcpd src/ tests/ --verbose ## PHP Mess Detector - - phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php - ## PHPLOC - #- php phploc.phar src/ + - ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ## PHPUnit - - phpunit -c ./ --coverage-text --coverage-html ./build/coverage + - ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./build/coverage + ## PHPLOC + - ./vendor/bin/phploc src/ ## PHPDocumentor - - vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" + - ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" after_script: ## PHPDocumentor diff --git a/composer.json b/composer.json index 2f9a0915..add1dc1d 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,9 @@ "phpunit/phpunit": "3.7.*", "phpdocumentor/phpdocumentor":"2.*", "squizlabs/php_codesniffer": "1.*", + "phpmd/phpmd": "dev-master", + "sebastian/phpcpd": "*", + "phploc/phploc": "*", "dompdf/dompdf":"0.6.*", "tecnick.com/tcpdf": "6.*", "mpdf/mpdf": "5.*" diff --git a/composer.lock b/composer.lock index 11a38043..d9cf9adf 100644 --- a/composer.lock +++ b/composer.lock @@ -1,9 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" ], - "hash": "7d0a883164ca8e64ca34f4910aa64b96", + "hash": "8ffa35e0864738ed4325f961b941c0d2", "packages": [ ], @@ -706,6 +707,45 @@ ], "time": "2013-08-25 17:11:40" }, + { + "name": "pdepend/pdepend", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/pdepend/pdepend.git", + "reference": "b74f2bb68e86104cd97dfb8d74209692c9b465ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/b74f2bb68e86104cd97dfb8d74209692c9b465ce", + "reference": "b74f2bb68e86104cd97dfb8d74209692c9b465ce", + "shasum": "" + }, + "require": { + "symfony/config": "@stable", + "symfony/dependency-injection": "@stable", + "symfony/filesystem": "@stable" + }, + "require-dev": { + "phpunit/phpunit": "3.*@stable", + "squizlabs/php_codesniffer": "@stable" + }, + "bin": [ + "src/bin/pdepend" + ], + "type": "library", + "autoload": { + "psr-0": { + "PDepend\\": "src/main/php/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Official version of pdepend to be handled with Composer", + "time": "2014-05-21 09:48:10" + }, { "name": "phenx/php-font-lib", "version": "0.2.2", @@ -1406,6 +1446,98 @@ ], "time": "2013-09-09 06:13:02" }, + { + "name": "phploc/phploc", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phploc.git", + "reference": "d177c22e2a08e448f7bdfa762045f7bd086834d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phploc/zipball/d177c22e2a08e448f7bdfa762045f7bd086834d7", + "reference": "d177c22e2a08e448f7bdfa762045f7bd086834d7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/finder-facade": ">=1.1.0", + "sebastian/git": ">=1.0.0", + "sebastian/version": ">=1.0.3", + "symfony/console": ">=2.2.0" + }, + "bin": [ + "phploc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "A tool for quickly measuring the size of a PHP project.", + "homepage": "https://github.com/sebastianbergmann/phploc", + "time": "2014-04-27 06:47:27" + }, + { + "name": "phpmd/phpmd", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpmd/phpmd.git", + "reference": "68ced5452910d3555a38720bd87f5f2356c5a003" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/68ced5452910d3555a38720bd87f5f2356c5a003", + "reference": "68ced5452910d3555a38720bd87f5f2356c5a003", + "shasum": "" + }, + "require": { + "pdepend/pdepend": "2.0.*", + "php": ">=5.3.0", + "symfony/config": "@stable", + "symfony/dependency-injection": "@stable", + "symfony/filesystem": "@stable" + }, + "bin": [ + "src/bin/phpmd" + ], + "type": "library", + "autoload": { + "psr-0": { + "PHPMD\\": "src/main/php", + "PDepend\\": "vendor/pdepend/pdepend/src/main/php/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "../../pdepend/pdepend/src/main/php", + "src/main/php" + ], + "license": [ + "BSD-3-Clause" + ], + "description": "Official version of PHPMD handled with Composer.", + "time": "2014-05-21 12:45:23" + }, { "name": "phpoption/phpoption", "version": "1.4.0", @@ -1907,6 +2039,177 @@ ], "time": "2012-12-21 11:40:51" }, + { + "name": "sebastian/finder-facade", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/finder-facade.git", + "reference": "1e396fda3449fce9df032749fa4fa2619e0347e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/1e396fda3449fce9df032749fa4fa2619e0347e0", + "reference": "1e396fda3449fce9df032749fa4fa2619e0347e0", + "shasum": "" + }, + "require": { + "symfony/finder": ">=2.2.0", + "theseer/fdomdocument": ">=1.3.1" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", + "homepage": "https://github.com/sebastianbergmann/finder-facade", + "time": "2013-05-28 06:10:03" + }, + { + "name": "sebastian/git", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/git.git", + "reference": "572c35353fefcc8607d6fef0e362a9f3a5e84d96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/git/zipball/572c35353fefcc8607d6fef0e362a9f3a5e84d96", + "reference": "572c35353fefcc8607d6fef0e362a9f3a5e84d96", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple wrapper for Git", + "homepage": "http://www.github.com/sebastianbergmann/git", + "keywords": [ + "git" + ], + "time": "2014-06-14 07:12:53" + }, + { + "name": "sebastian/phpcpd", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "a9462153f2dd90466a010179901d31fbff598365" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/a9462153f2dd90466a010179901d31fbff598365", + "reference": "a9462153f2dd90466a010179901d31fbff598365", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-timer": ">=1.0.4", + "sebastian/finder-facade": ">=1.1.0", + "sebastian/version": ">=1.0.3", + "symfony/console": ">=2.2.0", + "theseer/fdomdocument": "~1.4" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "time": "2014-03-31 09:25:30" + }, + { + "name": "sebastian/version", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43", + "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-03-07 15:35:33" + }, { "name": "squizlabs/php_codesniffer", "version": "1.5.3", @@ -2089,6 +2392,65 @@ "homepage": "http://symfony.com", "time": "2014-05-22 08:54:24" }, + { + "name": "symfony/dependency-injection", + "version": "v2.5.0", + "target-dir": "Symfony/Component/DependencyInjection", + "source": { + "type": "git", + "url": "https://github.com/symfony/DependencyInjection.git", + "reference": "5dfb4c2b74c4976efe1efa783370da656a2dd742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/5dfb4c2b74c4976efe1efa783370da656a2dd742", + "reference": "5dfb4c2b74c4976efe1efa783370da656a2dd742", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/config": "~2.2", + "symfony/expression-language": "~2.4", + "symfony/yaml": "~2.0" + }, + "suggest": { + "symfony/config": "", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\DependencyInjection\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony DependencyInjection Component", + "homepage": "http://symfony.com", + "time": "2014-05-12 09:28:39" + }, { "name": "symfony/event-dispatcher", "version": "v2.5.0", @@ -2524,11 +2886,11 @@ }, { "name": "tecnick.com/tcpdf", - "version": "6.0.083", + "version": "6.0.086", "source": { "type": "git", "url": "git://git.code.sf.net/p/tcpdf/code", - "reference": "d6a2206ab366f493680a22151429f17fd045fe04" + "reference": "b1c0cc74a84948029d8c9824736d9021871a63a7" }, "require": { "php": ">=5.3.0" @@ -2577,7 +2939,47 @@ "pdf417", "qrcode" ], - "time": "2014-05-29 18:28:56" + "time": "2014-06-20 15:28:34" + }, + { + "name": "theseer/fdomdocument", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/fDOMDocument.git", + "reference": "137aa3b13bef05b4e301899cbabdaf7d501847d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/137aa3b13bef05b4e301899cbabdaf7d501847d2", + "reference": "137aa3b13bef05b4e301899cbabdaf7d501847d2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "lib-libxml": "*", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "lead" + } + ], + "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", + "homepage": "https://github.com/theseer/fDOMDocument", + "time": "2014-02-19 00:20:43" }, { "name": "twig/twig", @@ -3219,9 +3621,9 @@ ], "minimum-stability": "stable", - "stability-flags": [ - - ], + "stability-flags": { + "phpmd/phpmd": 20 + }, "platform": { "php": ">=5.3.3", "ext-xml": "*" From ea6ec473d26fc529cbbe0b1f0725243deab39309 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 22 Jun 2014 10:22:40 +0700 Subject: [PATCH 280/326] Update composer dependencies --- composer.json | 8 +- composer.lock | 328 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 291 insertions(+), 45 deletions(-) diff --git a/composer.json b/composer.json index add1dc1d..798280d3 100644 --- a/composer.json +++ b/composer.json @@ -36,12 +36,12 @@ "ext-xml": "*" }, "require-dev": { - "phpunit/phpunit": "3.7.*", + "phpunit/phpunit": "4.*", "phpdocumentor/phpdocumentor":"2.*", "squizlabs/php_codesniffer": "1.*", - "phpmd/phpmd": "dev-master", - "sebastian/phpcpd": "*", - "phploc/phploc": "*", + "phpmd/phpmd": "2.*", + "sebastian/phpcpd": "2.*", + "phploc/phploc": "2.*", "dompdf/dompdf":"0.6.*", "tecnick.com/tcpdf": "6.*", "mpdf/mpdf": "5.*" diff --git a/composer.lock b/composer.lock index d9cf9adf..2d21196d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "8ffa35e0864738ed4325f961b941c0d2", + "hash": "cc4b56586d5cdffa05da9ee2cf50a622", "packages": [ ], @@ -1498,7 +1498,7 @@ }, { "name": "phpmd/phpmd", - "version": "dev-master", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", @@ -1589,40 +1589,44 @@ }, { "name": "phpunit/php-code-coverage", - "version": "1.2.17", + "version": "2.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34" + "reference": "58401826c8cfc8fd689b60026e91c337df374bca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", - "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/58401826c8cfc8fd689b60026e91c337df374bca", + "reference": "58401826c8cfc8fd689b60026e91c337df374bca", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.2.0@stable", - "phpunit/php-token-stream": ">=1.1.3@stable" + "phpunit/php-file-iterator": "~1.3.1", + "phpunit/php-text-template": "~1.2.0", + "phpunit/php-token-stream": "~1.2.2", + "sebastian/environment": "~1.0.0", + "sebastian/version": "~1.0.3" }, "require-dev": { - "phpunit/phpunit": "3.7.*@dev" + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4.0.14" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.0.5" + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ - "PHP/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1646,7 +1650,7 @@ "testing", "xunit" ], - "time": "2014-03-28 10:53:45" + "time": "2014-05-26 14:55:24" }, { "name": "phpunit/php-file-iterator", @@ -1833,51 +1837,52 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.37", + "version": "4.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc" + "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", - "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/939cb801b3b2aa253aedd0b279f40bb8f35cec91", + "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91", "shasum": "" }, "require": { - "ext-ctype": "*", "ext-dom": "*", "ext-json": "*", "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", "php": ">=5.3.3", - "phpunit/php-code-coverage": "~1.2", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.1", - "phpunit/php-timer": "~1.0", - "phpunit/phpunit-mock-objects": "~1.2", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.1", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.1", + "sebastian/comparator": "~1.0", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.0", + "sebastian/exporter": "~1.0", + "sebastian/version": "~1.0", "symfony/yaml": "~2.0" }, - "require-dev": { - "pear-pear.php.net/pear": "1.9.4" - }, "suggest": { "phpunit/php-invoker": "~1.1" }, "bin": [ - "composer/bin/phpunit" + "phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.7.x-dev" + "dev-master": "4.1.x-dev" } }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1902,33 +1907,41 @@ "testing", "xunit" ], - "time": "2014-04-30 12:24:19" + "time": "2014-06-11 14:15:47" }, { "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", + "version": "2.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" + "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f", + "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" }, "suggest": { "ext-soap": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1951,7 +1964,7 @@ "mock", "xunit" ], - "time": "2013-01-13 10:24:48" + "time": "2014-06-07 16:22:57" }, { "name": "pimple/pimple", @@ -2039,6 +2052,239 @@ ], "time": "2012-12-21 11:40:51" }, + { + "name": "sebastian/comparator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", + "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.1", + "sebastian/exporter": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2014-05-02 07:05:58" + }, + { + "name": "sebastian/diff", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", + "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2013-08-03 16:46:33" + }, + { + "name": "sebastian/environment", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/79517609ec01139cd7e9fded0dd7ce08c952ef6a", + "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2014-02-18 16:17:19" + }, + { + "name": "sebastian/exporter", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", + "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net", + "role": "Lead" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2014-02-16 08:26:31" + }, { "name": "sebastian/finder-facade", "version": "1.1.0", @@ -3621,9 +3867,9 @@ ], "minimum-stability": "stable", - "stability-flags": { - "phpmd/phpmd": 20 - }, + "stability-flags": [ + + ], "platform": { "php": ">=5.3.3", "ext-xml": "*" From 6e175abfcd2e7a7a69b46582cbdedda2235606bd Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 22 Jun 2014 11:12:26 +0700 Subject: [PATCH 281/326] Revert phpunit to 3.7.* because 4.* is too slow sebastianbergmann/phpunit#1300 --- composer.json | 2 +- composer.lock | 320 ++++++-------------------------------------------- 2 files changed, 38 insertions(+), 284 deletions(-) diff --git a/composer.json b/composer.json index 798280d3..74009e3a 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "ext-xml": "*" }, "require-dev": { - "phpunit/phpunit": "4.*", + "phpunit/phpunit": "3.7.*", "phpdocumentor/phpdocumentor":"2.*", "squizlabs/php_codesniffer": "1.*", "phpmd/phpmd": "2.*", diff --git a/composer.lock b/composer.lock index 2d21196d..122d7ab2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "cc4b56586d5cdffa05da9ee2cf50a622", + "hash": "50bae1209285a67796556b7ec42f64fc", "packages": [ ], @@ -1589,44 +1589,40 @@ }, { "name": "phpunit/php-code-coverage", - "version": "2.0.8", + "version": "1.2.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "58401826c8cfc8fd689b60026e91c337df374bca" + "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/58401826c8cfc8fd689b60026e91c337df374bca", - "reference": "58401826c8cfc8fd689b60026e91c337df374bca", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", + "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3.1", - "phpunit/php-text-template": "~1.2.0", - "phpunit/php-token-stream": "~1.2.2", - "sebastian/environment": "~1.0.0", - "sebastian/version": "~1.0.3" + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.2.0@stable", + "phpunit/php-token-stream": ">=1.1.3@stable" }, "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4.0.14" + "phpunit/phpunit": "3.7.*@dev" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" + "ext-xdebug": ">=2.0.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { "classmap": [ - "src/" + "PHP/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1650,7 +1646,7 @@ "testing", "xunit" ], - "time": "2014-05-26 14:55:24" + "time": "2014-03-28 10:53:45" }, { "name": "phpunit/php-file-iterator", @@ -1837,52 +1833,51 @@ }, { "name": "phpunit/phpunit", - "version": "4.1.3", + "version": "3.7.37", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91" + "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/939cb801b3b2aa253aedd0b279f40bb8f35cec91", - "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", + "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", "shasum": "" }, "require": { + "ext-ctype": "*", "ext-dom": "*", "ext-json": "*", "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", "php": ">=5.3.3", - "phpunit/php-code-coverage": "~2.0", - "phpunit/php-file-iterator": "~1.3.1", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "~1.0.2", - "phpunit/phpunit-mock-objects": "~2.1", - "sebastian/comparator": "~1.0", - "sebastian/diff": "~1.1", - "sebastian/environment": "~1.0", - "sebastian/exporter": "~1.0", - "sebastian/version": "~1.0", + "phpunit/php-code-coverage": "~1.2", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.1", + "phpunit/php-timer": "~1.0", + "phpunit/phpunit-mock-objects": "~1.2", "symfony/yaml": "~2.0" }, + "require-dev": { + "pear-pear.php.net/pear": "1.9.4" + }, "suggest": { "phpunit/php-invoker": "~1.1" }, "bin": [ - "phpunit" + "composer/bin/phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1.x-dev" + "dev-master": "3.7.x-dev" } }, "autoload": { "classmap": [ - "src/" + "PHPUnit/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1907,41 +1902,33 @@ "testing", "xunit" ], - "time": "2014-06-11 14:15:47" + "time": "2014-04-30 12:24:19" }, { "name": "phpunit/phpunit-mock-objects", - "version": "2.1.4", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f" + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f", - "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.1" + "phpunit/php-text-template": ">=1.1.1@stable" }, "suggest": { "ext-soap": "*" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1.x-dev" - } - }, "autoload": { "classmap": [ - "src/" + "PHPUnit/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1964,7 +1951,7 @@ "mock", "xunit" ], - "time": "2014-06-07 16:22:57" + "time": "2013-01-13 10:24:48" }, { "name": "pimple/pimple", @@ -2052,239 +2039,6 @@ ], "time": "2012-12-21 11:40:51" }, - { - "name": "sebastian/comparator", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", - "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.1", - "sebastian/exporter": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2014-05-02 07:05:58" - }, - { - "name": "sebastian/diff", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", - "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "http://www.github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2013-08-03 16:46:33" - }, - { - "name": "sebastian/environment", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/79517609ec01139cd7e9fded0dd7ce08c952ef6a", - "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "4.0.*@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2014-02-18 16:17:19" - }, - { - "name": "sebastian/exporter", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", - "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "4.0.*@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net", - "role": "Lead" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2014-02-16 08:26:31" - }, { "name": "sebastian/finder-facade", "version": "1.1.0", From a5c857f7491522699da3ac00c47f5b7d98ed5339 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 24 Jun 2014 10:36:58 +0200 Subject: [PATCH 282/326] #289 : Update elements.rst --- docs/elements.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index e4baf70e..2f2fb91c 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -397,7 +397,23 @@ To be completed. Lines ----- -To be completed. +Line elements can be added to sections by using ``addLine``. + +.. code-block:: php + + $linestyle = array('weight' => 1, 'width' => 100, 'height' => 0, 'color' => 635552); + $section->addLine($lineStyle) + +Available line style attributes: + +- ``weight`` Line width in twips +- ``color`` Defines the color of stroke +- ``dash`` Line types: dash, rounddot, squaredot, dashdot, longdash, longdashdot, longdashdotdot +- ``beginArrow`` Start type of arrow: block, open, classic, diamond, oval +- ``endArrow`` End type of arrow: block, open, classic, diamond, ovel +- ``width`` Line-object width in pt +- ``height`` Line-object height in pt +- ``flip`` Flip the line element: true, false Shapes ------ From b5a63c5b55a77e9d75dc52439f9b60587ac76a20 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 28 Jun 2014 11:47:04 +0700 Subject: [PATCH 283/326] Elaborate SDT elements --- CHANGELOG.md | 1 + samples/Sample_34_SDT.php | 13 +++- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 63 +++++++++++++++---- .../Tests/Writer/Word2007/ElementTest.php | 20 ++++++ 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22f22dd9..6f9bf239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin GH-266 - Setting: Ability to define document protection (readOnly, comments, trackedChanges, forms) - @ivanlanin - Setting: Ability to remove [Compatibility Mode] text in the MS Word title bar - @ivanlanin +- SDT: Ability to add structured document tag elements (comboBox, dropDownList, date) - @ivanlanin ### Bugfixes diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index fc1e7de6..241dee2a 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -4,11 +4,20 @@ include_once 'Sample_Header.php'; // New Word document echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$phpWord->getProtection()->setEditing('forms'); $section = $phpWord->addSection(); -$section->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); +$textrun = $section->addTextRun(); +$textrun->addText('Combobox: '); +$textrun->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); + +$textrun = $section->addTextRun(); +$textrun->addText('Date: '); +$textrun->addSDT('date'); + +$textrun = $section->addTextRun(); +$textrun->addText('Drop down list: '); +$textrun->addSDT('dropDownList')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index afde4270..b934b2d8 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -193,6 +193,7 @@ abstract class AbstractContainer extends AbstractElement 'Line' => $allContainers, 'Shape' => $allContainers, 'FormField' => $allContainers, + 'SDT' => $allContainers, 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), @@ -206,7 +207,6 @@ abstract class AbstractContainer extends AbstractElement 'TOC' => array('Section'), 'PageBreak' => array('Section'), 'Chart' => array('Section'), - 'SDT' => array('Section'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index d25eaf98..94578e16 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -39,33 +39,72 @@ class SDT extends Text return; } $type = $element->getType(); - $listItems = $element->getListItems(); + $writeFormField = "write{$type}"; $this->startElementP(); $xmlWriter->startElement('w:sdt'); + // Properties $xmlWriter->startElement('w:sdtPr'); $xmlWriter->writeElementBlock('w:id', 'w:val', rand(100000000, 999999999)); $xmlWriter->writeElementBlock('w:lock', 'w:val', 'sdtLocked'); - - $xmlWriter->startElement('w:placeholder'); - $xmlWriter->writeElementBlock('w:docPart', 'w:val', 'string'); - $xmlWriter->endElement(); // w:placeholder - - $xmlWriter->startElement("w:{$type}"); - foreach ($listItems as $key => $val) { - $xmlWriter->writeElementBlock('w:listItem', array('w:value' => $key, 'w:displayText' => $val)); - } - $xmlWriter->endElement(); // w:{$type} - + $this->$writeFormField($xmlWriter, $element); $xmlWriter->endElement(); // w:sdtPr + // Content $xmlWriter->startElement('w:sdtContent'); + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeRaw('Pick value'); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:sdtContent $xmlWriter->endElement(); // w:sdt $this->endElementP(); // w:p } + + /** + * Write combo box + * + * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html + */ + private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) + { + $type = $element->getType(); + $listItems = $element->getListItems(); + + $xmlWriter->startElement("w:{$type}"); + foreach ($listItems as $key => $val) { + $xmlWriter->writeElementBlock('w:listItem', array('w:value' => $key, 'w:displayText' => $val)); + } + $xmlWriter->endElement(); // w:{$type} + } + + /** + * Write drop down list + * + * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html + */ + private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) + { + $this->writecomboBox($xmlWriter, $element); + } + + /** + * Write date + * + * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html + */ + private function writeDate(XMLWriter $xmlWriter, SDTElement $element) + { + $xmlWriter->startElement("w:date"); + $xmlWriter->writeElementBlock('w:dateFormat', 'w:val', 'd/M/yyyy'); + $xmlWriter->writeElementBlock('w:lid', 'w:val', 'en-US'); + $xmlWriter->writeElementBlock('w:storeMappedDataAs', 'w:val', 'dateTime'); + $xmlWriter->writeElementBlock('w:calendar', 'w:val', 'gregorian'); + $xmlWriter->endElement(); // w:date + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 752415a1..92a74c15 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -196,4 +196,24 @@ class ElementTest extends \PHPUnit_Framework_TestCase $this->assertTrue($doc->elementExists($path . '/w:checkBox')); $this->assertTrue($doc->elementExists($path . '/w:ddList')); } + + /** + * Test SDT elements + */ + public function testSDTElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $section->addSDT('comboBox'); + $section->addSDT('dropDownList'); + $section->addSDT('date'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = "/w:document/w:body/w:p/w:sdt/w:sdtPr"; + $this->assertTrue($doc->elementExists($path . '/w:comboBox')); + $this->assertTrue($doc->elementExists($path . '/w:dropDownList')); + $this->assertTrue($doc->elementExists($path . '/w:date')); + } } From 689a7371cd0cd7c6929e86b9f6915bca811b5bd1 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 28 Jun 2014 12:01:53 +0700 Subject: [PATCH 284/326] Fix Travis errors --- src/PhpWord/Writer/Word2007/Element/SDT.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 94578e16..b41bb696 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -25,6 +25,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; * * @since 0.12.0 * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class SDT extends Text { @@ -100,7 +101,9 @@ class SDT extends Text */ private function writeDate(XMLWriter $xmlWriter, SDTElement $element) { - $xmlWriter->startElement("w:date"); + $type = $element->getType(); + + $xmlWriter->startElement("w:{$type}"); $xmlWriter->writeElementBlock('w:dateFormat', 'w:val', 'd/M/yyyy'); $xmlWriter->writeElementBlock('w:lid', 'w:val', 'en-US'); $xmlWriter->writeElementBlock('w:storeMappedDataAs', 'w:val', 'dateTime'); From 33570f7cd4e760cbb1c9e1ef26868f6805345907 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 28 Jun 2014 22:59:00 +0700 Subject: [PATCH 285/326] #294: Support for paragraph with borders --- CHANGELOG.md | 1 + src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Writer/Word2007/Style/Paragraph.php | 12 ++++++++++++ .../Tests/Writer/Word2007/Part/DocumentTest.php | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f9bf239..0ba632cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Setting: Ability to define document protection (readOnly, comments, trackedChanges, forms) - @ivanlanin - Setting: Ability to remove [Compatibility Mode] text in the MS Word title bar - @ivanlanin - SDT: Ability to add structured document tag elements (comboBox, dropDownList, date) - @ivanlanin +- Paragraph: Support for paragraph with borders - @ivanlanin GH-294 ### Bugfixes diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 18254321..964a4ec9 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -47,7 +47,7 @@ use PhpOffice\PhpWord\Shared\String; * * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html */ -class Paragraph extends AbstractStyle +class Paragraph extends Border { /** * @const int One line height equals 240 twip diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index f8d6cf1e..86efda2f 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -108,6 +108,18 @@ class Paragraph extends AbstractStyle // Numbering $this->writeNumbering($xmlWriter, $styles['numbering']); + // Border + if ($style->hasBorder()) { + $xmlWriter->startElement('w:pBdr'); + + $styleWriter = new MarginBorder($xmlWriter); + $styleWriter->setSizes($style->getBorderSize()); + $styleWriter->setColors($style->getBorderColor()); + $styleWriter->write(); + + $xmlWriter->endElement(); + } + if (!$this->withoutPPR) { $xmlWriter->endElement(); // w:pPr } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 56be15d0..ef36e0dd 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -139,6 +139,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase 'align' => 'center', 'tabs' => $tabs, 'shading' => array('fill' => 'FFFF99'), + 'borderSize' => 4, )); // Style #1 $phpWord->addFontStyle('fStyle', array('size' => '20', 'bold' => true, 'allCaps' => true, 'scale' => 200, 'spacing' => 240, 'kerning' => 10)); // Style #2 From 415d9b95c4fbefabb00d55f28d1481da3b86a17c Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 29 Jun 2014 14:10:49 +0700 Subject: [PATCH 286/326] Update tests --- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/PhpWord.php | 9 ++- .../Tests/Element/AbstractElementTest.php | 2 - tests/PhpWord/Tests/Element/SDTTest.php | 69 +++++++++++++++++++ tests/PhpWord/Tests/PhpWordTest.php | 12 ++++ tests/PhpWord/Tests/Shared/StringTest.php | 8 +++ 6 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 tests/PhpWord/Tests/Element/SDTTest.php diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 477c50f3..c69ed427 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -77,7 +77,7 @@ class SDT extends Text public function setType($value) { $enum = array('comboBox', 'dropDownList', 'date'); - $this->type = $this->setEnumVal($value, $enum, $this->type); + $this->type = $this->setEnumVal($value, $enum, 'comboBox'); return $this; } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index be808f01..7c5cbbfe 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -99,14 +99,10 @@ class PhpWord /** * Dynamic function call to reduce static dependency * - * Usage: - * - Getting and adding collections (Titles, Footnotes, and Endnotes) - * - Adding style - * * @param mixed $function * @param mixed $args + * @throws \BadMethodCallException * @return mixed - * * @since 0.12.0 */ public function __call($function, $args) @@ -149,6 +145,9 @@ class PhpWord if (in_array($function, $addStyle)) { return forward_static_call_array(array('PhpOffice\\PhpWord\\Style', $function), $args); } + + // Exception + throw new \BadMethodCallException("Method $function is not defined."); } /** diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Tests/Element/AbstractElementTest.php index c92469f3..180dd4d0 100644 --- a/tests/PhpWord/Tests/Element/AbstractElementTest.php +++ b/tests/PhpWord/Tests/Element/AbstractElementTest.php @@ -19,8 +19,6 @@ namespace PhpOffice\PhpWord\Tests\Element; /** * Test class for PhpOffice\PhpWord\Element\AbstractElement - * - * @runTestsInSeparateProcesses */ class AbstractElementTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/PhpWord/Tests/Element/SDTTest.php b/tests/PhpWord/Tests/Element/SDTTest.php new file mode 100644 index 00000000..aa7e89b3 --- /dev/null +++ b/tests/PhpWord/Tests/Element/SDTTest.php @@ -0,0 +1,69 @@ +setValue($value);; + $object->setListItems($types);; + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\SDT', $object); + $this->assertEquals($type, $object->getType()); + $this->assertEquals($types, $object->getListItems()); + $this->assertEquals($value, $object->getValue()); + } + + /** + * Test set type exception + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid style value + */ + public function testSetTypeException() + { + $object = new SDT('comboBox'); + $object->setType('foo'); + } + + /** + * Test set type + */ + public function testSetTypeNull() + { + $object = new SDT('comboBox'); + $object->setType(' '); + + $this->assertEquals('comboBox', $object->getType()); + } +} diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 75b2d288..756f848f 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -157,4 +157,16 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase $this->assertTrue($phpWord->save('test.docx', 'Word2007', true)); } + + /** + * Test calling undefined method + * + * @expectedException \BadMethodCallException + * @expectedExceptionMessage is not defined + */ + public function testCallUndefinedMethod() + { + $phpWord = new PhpWord(); + $phpWord->undefinedMethod(); + } } diff --git a/tests/PhpWord/Tests/Shared/StringTest.php b/tests/PhpWord/Tests/Shared/StringTest.php index bf5862fb..a3524ede 100644 --- a/tests/PhpWord/Tests/Shared/StringTest.php +++ b/tests/PhpWord/Tests/Shared/StringTest.php @@ -64,4 +64,12 @@ class StringTest extends \PHPUnit_Framework_TestCase $this->assertEquals('\uc0{\u8364}', String::toUnicode('€')); $this->assertEquals('\uc0{\u233}', String::toUnicode('é')); } + + /** + * Test remove underscore prefix + */ + public function testRemoveUnderscorePrefix() + { + $this->assertEquals('item', String::removeUnderscorePrefix('_item')); + } } From 40e41342ce87c5571277422d2562d64241115f35 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 29 Jun 2014 21:14:10 +0700 Subject: [PATCH 287/326] Fix PHPCS --- tests/PhpWord/Tests/Element/SDTTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Tests/Element/SDTTest.php b/tests/PhpWord/Tests/Element/SDTTest.php index aa7e89b3..8c7b4bf3 100644 --- a/tests/PhpWord/Tests/Element/SDTTest.php +++ b/tests/PhpWord/Tests/Element/SDTTest.php @@ -35,8 +35,8 @@ class SDTTest extends \PHPUnit_Framework_TestCase $type = $types[rand(0, 2)]; $value = rand(0, 100); $object = new SDT($type); - $object->setValue($value);; - $object->setListItems($types);; + $object->setValue($value); + $object->setListItems($types); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\SDT', $object); $this->assertEquals($type, $object->getType()); From d8aef5c502e9ec980f93b1647489c30bf4fe73a6 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 1 Jul 2014 09:52:24 +0700 Subject: [PATCH 288/326] Bugfix #294: `add` of container should be case insensitive --- CHANGELOG.md | 1 + src/PhpWord/Element/AbstractContainer.php | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ba632cf..eae842bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich GH-270 - Page breaks on titles and tables - @ivanlanin GH-274 - Table inside vertical border does not rendered properly - @ivanlanin GH-280 +- `add` of container should be case insensitive, e.g. `addToc` should be accepted, not only `addTOC` - @ivanlanin GH-294 ### Deprecated diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index b934b2d8..686644eb 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -77,18 +77,22 @@ abstract class AbstractContainer extends AbstractElement */ public function __call($function, $args) { - $elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', - 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', - 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', - 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField', 'SDT'); + $elements = array( + 'Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', + 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', + 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', + 'Line', 'Shape', 'Title', 'TOC', 'PageBreak', + 'Chart', 'FormField', 'SDT' + ); $functions = array(); - for ($i = 0; $i < count($elements); $i++) { - $functions[$i] = 'add' . $elements[$i]; + foreach ($elements as $element) { + $functions['add' . strtolower($element)] = $element; } // Run valid `add` command - if (in_array($function, $functions)) { - $element = str_replace('add', '', $function); + $function = strtolower($function); + if (array_key_exists($function, $functions)) { + $element = $functions[$function]; // Special case for TextBreak // @todo Remove the `$count` parameter in 1.0.0 to make this element similiar to other elements? From 3c694ea572304c0680b3ce4c5da193f433554a1d Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 2 Jul 2014 12:42:50 +0400 Subject: [PATCH 289/326] [NEW] Introduced CreateTemporaryFileException. --- .../CreateTemporaryFileException.php | 30 ++++++++++++++ src/PhpWord/Template.php | 20 ++++++---- .../CreateTemporaryFileExceptionTest.php | 39 +++++++++++++++++++ 3 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 src/PhpWord/Exception/CreateTemporaryFileException.php create mode 100644 tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php new file mode 100644 index 00000000..f635dd6b --- /dev/null +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -0,0 +1,30 @@ +message); + } +} diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 21e8b988..6cfa664f 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord; +use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\ZipArchive; @@ -54,24 +55,20 @@ class Template */ private $headerXMLs = array(); - /** - * Document footer XML - * - * @var string[] - */ - private $footerXMLs = array(); - /** * Create a new Template Object * + * @since 0.12.0 Throws CreateTemporaryFileException instead of Exception. + * * @param string $strFilename + * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct($strFilename) { $this->tempFileName = tempnam(sys_get_temp_dir(), ''); if ($this->tempFileName === false) { - throw new Exception('Could not create temporary file with unique name in the default temporary directory.'); + throw new CreateTemporaryFileException(); } // Copy the source File to the temp File @@ -98,6 +95,13 @@ class Template $this->documentXML = $this->zipClass->getFromName('word/document.xml'); } + /** + * Document footer XML + * + * @var string[] + */ + private $footerXMLs = array(); + /** * Applies XSL style sheet to template's parts * diff --git a/tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php new file mode 100644 index 00000000..7cf0cb77 --- /dev/null +++ b/tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php @@ -0,0 +1,39 @@ + Date: Wed, 2 Jul 2014 12:49:18 +0400 Subject: [PATCH 290/326] [NEW] Introduced CreateTemporaryFileException. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eae842bf..53533148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - PclZip: Remove temporary file after used - @andrew-kzoo GH-265 - Autoloader: Add the ability to set the autoloader options - @bskrtich GH-267 - Element: Refactor elements to move set relation Id from container to element - @ivanlanin +- Introduced CreateTemporaryFileException - @RomanSyroeshko ## 0.11.1 - 2 June 2014 From dbc9737136801e0fa3c40a8862df8a54c6b987a8 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 2 Jul 2014 12:58:55 +0400 Subject: [PATCH 291/326] [NEW] Introduced CreateTemporaryFileException. --- src/PhpWord/Exception/CreateTemporaryFileException.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index f635dd6b..9cddb7ac 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -24,7 +24,8 @@ final class CreateTemporaryFileException extends Exception { protected $message = 'Could not create a temporary file with unique name in the specified directory.'; - final public function __construct() { + final public function __construct() + { parent::__construct($this->message); } } From 369f55a71fee63d6d77aea8b9d935d322139a64e Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 2 Jul 2014 13:17:13 +0400 Subject: [PATCH 292/326] [NEW] Introduced CreateTemporaryFileException. --- .../Exception/CreateTemporaryFileException.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index 9cddb7ac..b68569c9 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -22,10 +22,16 @@ namespace PhpOffice\PhpWord\Exception; */ final class CreateTemporaryFileException extends Exception { - protected $message = 'Could not create a temporary file with unique name in the specified directory.'; - - final public function __construct() + /** + * @param integer $code The user defined exception code. + * @param \Exception $previous The previous exception used for the exception chaining. + */ + final public function __construct($code = 0, \Exception $previous = null) { - parent::__construct($this->message); + parent::__construct( + 'Could not create a temporary file with unique name in the specified directory.', + $code, + $previous + ); } } From 75c8e7e8166d0946ca604984875d8866203af907 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 2 Jul 2014 17:21:43 +0400 Subject: [PATCH 293/326] [NEW] Introduced CopyFileException. --- CHANGELOG.md | 2 +- src/PhpWord/Exception/CopyFileException.php | 39 +++++++++++++++++++ src/PhpWord/Template.php | 9 +++-- src/PhpWord/Writer/AbstractWriter.php | 7 +++- .../Tests/Exception/CopyFileExceptionTest.php | 39 +++++++++++++++++++ 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 src/PhpWord/Exception/CopyFileException.php create mode 100644 tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 53533148..f1ac091e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - PclZip: Remove temporary file after used - @andrew-kzoo GH-265 - Autoloader: Add the ability to set the autoloader options - @bskrtich GH-267 - Element: Refactor elements to move set relation Id from container to element - @ivanlanin -- Introduced CreateTemporaryFileException - @RomanSyroeshko +- Introduced CreateTemporaryFileException, CopyFileException - @RomanSyroeshko ## 0.11.1 - 2 June 2014 diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php new file mode 100644 index 00000000..97a900e3 --- /dev/null +++ b/src/PhpWord/Exception/CopyFileException.php @@ -0,0 +1,39 @@ +tempFileName)) { - throw new Exception("Could not copy the template from {$strFilename} to {$this->tempFileName}."); + if (false === copy($strFilename, $this->tempFileName)) { + throw new CopyFileException($strFilename, $this->tempFileName); } $this->zipClass = new ZipArchive(); diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 346e9b66..8e7cb71d 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer; +use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\ZipArchive; @@ -233,14 +234,16 @@ abstract class AbstractWriter implements WriterInterface /** * Cleanup temporary file + * + * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ protected function cleanupTempFile() { if ($this->originalFilename != $this->tempFilename) { // @codeCoverageIgnoreStart // Can't find any test case. Uncomment when found. - if (copy($this->tempFilename, $this->originalFilename) === false) { - throw new Exception("Could not copy temporary zip file."); + if (false === copy($this->tempFilename, $this->originalFilename)) { + throw new CopyFileException($this->tempFilename, $this->originalFilename); } // @codeCoverageIgnoreEnd @unlink($this->tempFilename); diff --git a/tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php new file mode 100644 index 00000000..3d92595f --- /dev/null +++ b/tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php @@ -0,0 +1,39 @@ + Date: Wed, 2 Jul 2014 17:44:26 +0400 Subject: [PATCH 294/326] [Changed] Refactored Template a little. --- src/PhpWord/Template.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index e37b21dd..3c6065ff 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -29,7 +29,7 @@ use PhpOffice\PhpWord\Shared\ZipArchive; class Template { /** - * ZipArchive object + * ZipArchive object. * * @var mixed */ @@ -61,20 +61,20 @@ class Template * * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * - * @param string $strFilename + * @param string $fileName The fully qualified template file name. * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ - public function __construct($strFilename) + public function __construct($fileName) { $this->tempFileName = tempnam(sys_get_temp_dir(), ''); - if ($this->tempFileName === false) { + if (false === $this->tempFileName) { throw new CreateTemporaryFileException(); } // Copy the source File to the temp File - if (false === copy($strFilename, $this->tempFileName)) { - throw new CopyFileException($strFilename, $this->tempFileName); + if (false === copy($fileName, $this->tempFileName)) { + throw new CopyFileException($fileName, $this->tempFileName); } $this->zipClass = new ZipArchive(); @@ -117,17 +117,17 @@ class Template $processor->importStylesheet($xslDOMDocument); - if ($processor->setParameter($xslOptionsURI, $xslOptions) === false) { + if (false === $processor->setParameter($xslOptionsURI, $xslOptions)) { throw new Exception('Could not set values for the given XSL style sheet parameters.'); } $xmlDOMDocument = new \DOMDocument(); - if ($xmlDOMDocument->loadXML($this->documentXML) === false) { + if (false === $xmlDOMDocument->loadXML($this->documentXML)) { throw new Exception('Could not load XML from the given template.'); } $xmlTransformed = $processor->transformToXml($xmlDOMDocument); - if ($xmlTransformed === false) { + if (false === $xmlTransformed) { throw new Exception('Could not transform the given XML document.'); } @@ -317,7 +317,7 @@ class Template } // Close zip file - if ($this->zipClass->close() === false) { + if (false === $this->zipClass->close()) { throw new Exception('Could not close zip file.'); } @@ -327,18 +327,18 @@ class Template /** * Save XML to defined name * - * @param string $strFilename + * @param string $fileName * @since 0.8.0 */ - public function saveAs($strFilename) + public function saveAs($fileName) { - $tempFilename = $this->save(); + $tempFileName = $this->save(); - if (file_exists($strFilename)) { - unlink($strFilename); + if (file_exists($fileName)) { + unlink($fileName); } - rename($tempFilename, $strFilename); + rename($tempFileName, $fileName); } /** From e1164f8989642a3f212ea491f0c0233b7b9b8f80 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 2 Jul 2014 17:49:53 +0400 Subject: [PATCH 295/326] [Changed] Refactored Template a little. --- src/PhpWord/Template.php | 52 ++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 3c6065ff..fc224d14 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -36,28 +36,28 @@ class Template private $zipClass; /** - * Temporary file name + * Temporary file name. * * @var string */ private $tempFileName; /** - * Document XML + * Document XML. * * @var string */ private $documentXML; /** - * Document header XML + * Document header XML. * * @var string[] */ private $headerXMLs = array(); /** - * Create a new Template Object + * Create a new Template Object. * * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * @@ -97,18 +97,19 @@ class Template } /** - * Document footer XML + * Document footer XML. * * @var string[] */ private $footerXMLs = array(); /** - * Applies XSL style sheet to template's parts + * Applies XSL style sheet to template's parts. * * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI + * @return void * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') @@ -135,11 +136,12 @@ class Template } /** - * Set a Template value + * Set a Template value. * * @param mixed $search * @param mixed $replace * @param integer $limit + * @return void */ public function setValue($search, $replace, $limit = -1) { @@ -155,7 +157,8 @@ class Template } /** - * Returns array of all variables in template + * Returns array of all variables in template. + * * @return string[] */ public function getVariables() @@ -174,7 +177,7 @@ class Template } /** - * Clone a table row in a template document + * Clone a table row in a template document. * * @param string $search * @param integer $numberOfClones @@ -230,7 +233,7 @@ class Template } /** - * Clone a block + * Clone a block. * * @param string $blockname * @param integer $clones @@ -266,10 +269,11 @@ class Template } /** - * Replace a block + * Replace a block. * * @param string $blockname * @param string $replacement + * @return void */ public function replaceBlock($blockname, $replacement) { @@ -289,9 +293,10 @@ class Template } /** - * Delete a block of text + * Delete a block of text. * * @param string $blockname + * @return void */ public function deleteBlock($blockname) { @@ -299,7 +304,7 @@ class Template } /** - * Save XML to temporary file + * Save XML to temporary file. * * @return string * @throws \PhpOffice\PhpWord\Exception\Exception @@ -325,10 +330,12 @@ class Template } /** - * Save XML to defined name + * Save XML to defined name. + * + * @since 0.8.0 * * @param string $fileName - * @since 0.8.0 + * @return void */ public function saveAs($fileName) { @@ -375,7 +382,8 @@ class Template } /** - * Find all variables in $documentPartXML + * Find all variables in $documentPartXML. + * * @param string $documentPartXML * @return string[] */ @@ -387,7 +395,8 @@ class Template } /** - * Get the name of the footer file for $index + * Get the name of the footer file for $index. + * * @param integer $index * @return string */ @@ -397,7 +406,8 @@ class Template } /** - * Get the name of the header file for $index + * Get the name of the header file for $index. + * * @param integer $index * @return string */ @@ -407,7 +417,7 @@ class Template } /** - * Find the start position of the nearest table row before $offset + * Find the start position of the nearest table row before $offset. * * @param integer $offset * @return integer @@ -426,7 +436,7 @@ class Template } /** - * Find the end position of the nearest table row after $offset + * Find the end position of the nearest table row after $offset. * * @param integer $offset * @return integer @@ -438,7 +448,7 @@ class Template } /** - * Get a slice of a string + * Get a slice of a string. * * @param integer $startPosition * @param integer $endPosition From 20d986b11dcf28c0210ff28279a6844f16b4077b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 3 Jul 2014 11:44:10 +0400 Subject: [PATCH 296/326] [CHANGED] Documentation on Zip API providers. --- docs/general.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index c6a893bc..8fc7130e 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -75,11 +75,10 @@ during development to make the resulting XML file easier to read. Zip class ~~~~~~~~~ -By default, PHPWord uses PHP -`ZipArchive `__ to read or write -ZIP compressed archive and the files inside them. If you can't have -ZipArchive installed on your server, you can use pure PHP library -alternative, `PCLZip `__, which +By default, PHPWord uses `Zip extension `__ +to deal with ZIP compressed archives and files inside them. If you can't have +Zip extension installed on your server, you can use pure PHP library +alternative, `PclZip `__, which included with PHPWord. .. code-block:: php From d0a609bc958e4c0d3b69e178d6220f61ef1cba09 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 3 Jul 2014 15:40:24 +0400 Subject: [PATCH 297/326] [CHANGED] Added "@return" annotation where it as missed. --- src/PhpWord/Autoloader.php | 1 + src/PhpWord/Collection/AbstractCollection.php | 3 +- src/PhpWord/Element/AbstractElement.php | 25 +++++++--- src/PhpWord/Element/Chart.php | 4 +- src/PhpWord/Element/Footer.php | 6 ++- src/PhpWord/Element/Image.php | 19 ++++--- src/PhpWord/Element/ListItemRun.php | 8 ++- src/PhpWord/Element/Object.php | 3 +- src/PhpWord/Element/Section.php | 3 +- src/PhpWord/Element/TOC.php | 6 ++- src/PhpWord/Element/Table.php | 3 +- src/PhpWord/PhpWord.php | 6 ++- src/PhpWord/Reader/ODText.php | 3 +- src/PhpWord/Reader/ODText/Content.php | 3 +- src/PhpWord/Reader/ODText/Meta.php | 3 +- src/PhpWord/Reader/RTF/Document.php | 49 +++++++++++++------ src/PhpWord/Reader/Word2007.php | 3 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 18 ++++--- src/PhpWord/Reader/Word2007/DocPropsCore.php | 3 +- .../Reader/Word2007/DocPropsCustom.php | 3 +- src/PhpWord/Reader/Word2007/Document.php | 14 ++++-- src/PhpWord/Reader/Word2007/Footnotes.php | 3 +- src/PhpWord/Reader/Word2007/Numbering.php | 3 +- src/PhpWord/Reader/Word2007/Styles.php | 3 +- src/PhpWord/Settings.php | 8 ++- src/PhpWord/Shared/Html.php | 9 ++-- src/PhpWord/Shared/String.php | 4 +- src/PhpWord/Shared/XMLWriter.php | 3 ++ src/PhpWord/Style.php | 5 +- src/PhpWord/Style/Cell.php | 16 ++++-- src/PhpWord/Style/TextBox.php | 21 +++++--- src/PhpWord/Template.php | 1 + src/PhpWord/Writer/AbstractWriter.php | 26 ++++++---- src/PhpWord/Writer/HTML.php | 6 ++- .../Writer/HTML/Element/AbstractElement.php | 3 +- src/PhpWord/Writer/HTML/Element/Text.php | 10 ++-- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 3 +- src/PhpWord/Writer/HTML/Part/Head.php | 3 +- .../Writer/HTML/Style/AbstractStyle.php | 3 +- src/PhpWord/Writer/ODText.php | 5 +- .../Writer/ODText/Part/AbstractPart.php | 10 +++- src/PhpWord/Writer/ODText/Part/Content.php | 19 +++++-- src/PhpWord/Writer/ODText/Part/Meta.php | 1 + src/PhpWord/Writer/ODText/Part/Styles.php | 21 ++++++-- src/PhpWord/Writer/ODText/Style/Font.php | 4 +- src/PhpWord/Writer/ODText/Style/Image.php | 4 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 +- src/PhpWord/Writer/ODText/Style/Section.php | 4 +- src/PhpWord/Writer/ODText/Style/Table.php | 4 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 1 + src/PhpWord/Writer/PDF/DomPDF.php | 3 +- src/PhpWord/Writer/PDF/MPDF.php | 3 +- src/PhpWord/Writer/PDF/TCPDF.php | 3 +- src/PhpWord/Writer/RTF.php | 18 +++++-- .../Writer/RTF/Element/AbstractElement.php | 4 +- src/PhpWord/Writer/RTF/Part/Header.php | 23 ++++++--- src/PhpWord/Writer/RTF/Style/Border.php | 6 ++- src/PhpWord/Writer/RTF/Style/Font.php | 7 ++- src/PhpWord/Writer/RTF/Style/Paragraph.php | 3 +- src/PhpWord/Writer/Word2007.php | 16 ++++-- .../Word2007/Element/AbstractElement.php | 18 +++++-- src/PhpWord/Writer/Word2007/Element/Chart.php | 4 +- .../Writer/Word2007/Element/CheckBox.php | 4 +- .../Writer/Word2007/Element/Container.php | 6 ++- src/PhpWord/Writer/Word2007/Element/Field.php | 4 +- .../Writer/Word2007/Element/Footnote.php | 4 +- .../Writer/Word2007/Element/FormField.php | 19 +++++-- src/PhpWord/Writer/Word2007/Element/Image.php | 13 +++-- src/PhpWord/Writer/Word2007/Element/Line.php | 4 +- src/PhpWord/Writer/Word2007/Element/Link.php | 4 +- .../Writer/Word2007/Element/ListItem.php | 4 +- .../Writer/Word2007/Element/ListItemRun.php | 4 +- .../Writer/Word2007/Element/Object.php | 4 +- .../Writer/Word2007/Element/PageBreak.php | 3 +- .../Writer/Word2007/Element/PreserveText.php | 4 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 19 +++++-- src/PhpWord/Writer/Word2007/Element/Shape.php | 21 +++++--- src/PhpWord/Writer/Word2007/Element/TOC.php | 12 ++++- src/PhpWord/Writer/Word2007/Element/Table.php | 22 +++++++-- src/PhpWord/Writer/Word2007/Element/Text.php | 4 +- .../Writer/Word2007/Element/TextBox.php | 4 +- .../Writer/Word2007/Element/TextBreak.php | 4 +- .../Writer/Word2007/Element/TextRun.php | 4 +- src/PhpWord/Writer/Word2007/Element/Title.php | 4 +- .../Writer/Word2007/Part/AbstractPart.php | 3 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 25 +++++++--- .../Writer/Word2007/Part/ContentTypes.php | 1 + src/PhpWord/Writer/Word2007/Part/Document.php | 6 ++- .../Writer/Word2007/Part/FontTable.php | 4 +- .../Writer/Word2007/Part/Footnotes.php | 3 +- .../Writer/Word2007/Part/Numbering.php | 20 ++++++-- src/PhpWord/Writer/Word2007/Part/Rels.php | 9 ++-- src/PhpWord/Writer/Word2007/Part/Settings.php | 15 ++++-- src/PhpWord/Writer/Word2007/Part/Styles.php | 14 ++++-- .../Writer/Word2007/Style/AbstractStyle.php | 5 +- .../Writer/Word2007/Style/Alignment.php | 4 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 7 ++- .../Writer/Word2007/Style/Extrusion.php | 4 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 4 +- src/PhpWord/Writer/Word2007/Style/Font.php | 11 +++-- src/PhpWord/Writer/Word2007/Style/Frame.php | 11 +++-- .../Writer/Word2007/Style/Indentation.php | 4 +- src/PhpWord/Writer/Word2007/Style/Line.php | 3 +- .../Writer/Word2007/Style/LineNumbering.php | 4 +- .../Writer/Word2007/Style/MarginBorder.php | 16 ++++-- src/PhpWord/Writer/Word2007/Style/Outline.php | 4 +- .../Writer/Word2007/Style/Paragraph.php | 22 ++++++--- src/PhpWord/Writer/Word2007/Style/Row.php | 7 ++- src/PhpWord/Writer/Word2007/Style/Section.php | 4 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 4 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 4 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 4 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 4 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 4 +- src/PhpWord/Writer/Word2007/Style/Table.php | 40 ++++++++++++--- src/PhpWord/Writer/Word2007/Style/TextBox.php | 8 ++- 116 files changed, 688 insertions(+), 262 deletions(-) diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index dbc42187..68da845d 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -41,6 +41,7 @@ class Autoloader * Autoload * * @param string $class + * @return void */ public static function autoload($class) { diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index ae1b6efb..41e40e2e 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -57,10 +57,11 @@ abstract class AbstractCollection } /** - * Set item + * Set item. * * @param int $index * @param mixed $item + * @return void */ public function setItem($index, $item) { diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 3fd2e4d0..82aa543e 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -126,9 +126,10 @@ abstract class AbstractElement } /** - * Set PhpWord as reference + * Set PhpWord as reference. * - * @param \PhpOffice\PhpWord\PhpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @return void */ public function setPhpWord(PhpWord &$phpWord = null) { @@ -146,10 +147,11 @@ abstract class AbstractElement } /** - * Set doc part + * Set doc part. * * @param string $docPart * @param int $docPartId + * @return void */ public function setDocPart($docPart, $docPartId = 1) { @@ -203,9 +205,10 @@ abstract class AbstractElement } /** - * Set element index + * Set element index. * * @param int $value + * @return void */ public function setElementIndex($value) { @@ -223,7 +226,9 @@ abstract class AbstractElement } /** - * Set element unique ID from 6 first digit of md5 + * Set element unique ID from 6 first digit of md5. + * + * @return void */ public function setElementId() { @@ -241,9 +246,10 @@ abstract class AbstractElement } /** - * Set relation Id + * Set relation Id. * * @param int $value + * @return void */ public function setRelationId($value) { @@ -266,6 +272,7 @@ abstract class AbstractElement * Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell) * * @param \PhpOffice\PhpWord\Element\AbstractElement $container + * @return void */ public function setParentContainer(AbstractElement $container) { @@ -295,6 +302,8 @@ abstract class AbstractElement * * - Image element needs to be passed to Media object * - Icon needs to be set for Object element + * + * @return void */ private function setMediaRelation() { @@ -320,7 +329,9 @@ abstract class AbstractElement } /** - * Set relation Id for elements that will be registered in the Collection subnamespaces + * Set relation Id for elements that will be registered in the Collection subnamespaces. + * + * @return void */ private function setCollectionRelation() { diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 2d709b8c..66c59ff5 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -80,9 +80,10 @@ class Chart extends AbstractElement } /** - * Set type + * Set type. * * @param string $value + * @return void */ public function setType($value) { @@ -95,6 +96,7 @@ class Chart extends AbstractElement * * @param array $categories * @param array $values + * @return void */ public function addSeries($categories, $values) { diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 142ccfda..8e19eaf7 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -59,10 +59,12 @@ class Footer extends AbstractContainer } /** - * Set type + * Set type. + * + * @since 0.10.0 * * @param string $value - * @since 0.10.0 + * @return void */ public function setType($value = self::AUTO) { diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 532905f4..e48f703e 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -257,9 +257,10 @@ class Image extends AbstractElement } /** - * Set target file name + * Set target file name. * * @param string $value + * @return void */ public function setTarget($value) { @@ -277,9 +278,10 @@ class Image extends AbstractElement } /** - * Set media index + * Set media index. * * @param integer $value + * @return void */ public function setMediaIndex($value) { @@ -358,9 +360,10 @@ class Image extends AbstractElement } /** - * Check memory image, supported type, image functions, and proportional width/height + * Check memory image, supported type, image functions, and proportional width/height. * * @param string $source + * @return void * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ @@ -395,9 +398,10 @@ class Image extends AbstractElement } /** - * Set source type + * Set source type. * * @param string $source + * @return void */ private function setSourceType($source) { @@ -443,7 +447,9 @@ class Image extends AbstractElement } /** - * Set image functions and extensions + * Set image functions and extensions. + * + * @return void */ private function setFunctions() { @@ -476,10 +482,11 @@ class Image extends AbstractElement } /** - * Set proportional width/height if one dimension not available + * Set proportional width/height if one dimension not available. * * @param integer $actualWidth * @param integer $actualHeight + * @return void */ private function setProportionalSize($actualWidth, $actualHeight) { diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 82c6f1ab..1b77830d 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -65,7 +65,9 @@ class ListItemRun extends TextRun } /** - * Get ListItem style + * Get ListItem style. + * + * @return \PhpOffice\PhpWord\Style\ListItem */ public function getStyle() { @@ -73,7 +75,9 @@ class ListItemRun extends TextRun } /** - * Get ListItem depth + * Get ListItem depth. + * + * @return int */ public function getDepth() { diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index ae279ab0..31943ba6 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -129,9 +129,10 @@ class Object extends AbstractElement } /** - * Set Image Relation ID + * Set Image Relation ID. * * @param int $rId + * @return void */ public function setImageRelationId($rId) { diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 33c69795..d746f69b 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -66,9 +66,10 @@ class Section extends AbstractContainer } /** - * Set section style + * Set section style. * * @param array $style + * @return void */ public function setStyle($style = null) { diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index 9ac74554..a56d9ffe 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -129,9 +129,10 @@ class TOC extends AbstractElement } /** - * Set max depth + * Set max depth. * * @param int $value + * @return void */ public function setMaxDepth($value) { @@ -149,9 +150,10 @@ class TOC extends AbstractElement } /** - * Set min depth + * Set min depth. * * @param int $value + * @return void */ public function setMinDepth($value) { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 5e14d6bc..5f0b8f79 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -118,9 +118,10 @@ class Table extends AbstractElement } /** - * Set table width + * Set table width. * * @param int $width + * @return void */ public function setWidth($width) { diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 7c5cbbfe..3b991e23 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -218,9 +218,10 @@ class PhpWord } /** - * Set default font name + * Set default font name. * * @param string $fontName + * @return void */ public function setDefaultFontName($fontName) { @@ -238,9 +239,10 @@ class PhpWord } /** - * Set default font size + * Set default font size. * * @param int $fontSize + * @return void */ public function setDefaultFontSize($fontSize) { diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 19efdc51..d7d23c80 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -51,13 +51,14 @@ class ODText extends AbstractReader implements ReaderInterface } /** - * Read document part + * Read document part. * * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param array $relationships * @param string $partName * @param string $docFile * @param string $xmlFile + * @return void */ private function readPart(PhpWord &$phpWord, $relationships, $partName, $docFile, $xmlFile) { diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 034789ff..9feb669a 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -28,9 +28,10 @@ use PhpOffice\PhpWord\Shared\XMLReader; class Content extends AbstractPart { /** - * Read content.xml + * Read content.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 518884fd..827446f0 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -28,9 +28,10 @@ use PhpOffice\PhpWord\Shared\XMLReader; class Meta extends AbstractPart { /** - * Read meta.xml + * Read meta.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void * @todo Process property type */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index cb082fdc..26763576 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -130,6 +130,7 @@ class Document * - Pushes every other character into the text queue * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void * @todo Use `fread` stream for scalability */ public function read(PhpWord &$phpWord) @@ -181,7 +182,9 @@ class Document } /** - * Mark opening braket `{` character + * Mark opening braket `{` character. + * + * @return void */ private function markOpening() { @@ -190,7 +193,9 @@ class Document } /** - * Mark closing braket `}` character + * Mark closing braket `}` character. + * + * @return void */ private function markClosing() { @@ -199,7 +204,9 @@ class Document } /** - * Mark backslash `\` character + * Mark backslash `\` character. + * + * @return void */ private function markBackslash() { @@ -214,7 +221,9 @@ class Document } /** - * Mark newline character: Flush control word because it's not possible to span multiline + * Mark newline character: Flush control word because it's not possible to span multiline. + * + * @return void */ private function markNewline() { @@ -224,9 +233,10 @@ class Document } /** - * Flush control word or text + * Flush control word or text. * * @param bool $isControl + * @return void */ private function flush($isControl = false) { @@ -238,9 +248,10 @@ class Document } /** - * Flush control word + * Flush control word. * * @param bool $isControl + * @return void */ private function flushControl($isControl = false) { @@ -255,7 +266,9 @@ class Document } /** - * Flush text in queue + * Flush text in queue. + * + * @return void */ private function flushText() { @@ -279,9 +292,10 @@ class Document } /** - * Reset control word and first char state + * Reset control word and first char state. * * @param bool $value + * @return void */ private function setControl($value) { @@ -290,9 +304,10 @@ class Document } /** - * Push text into queue + * Push text into queue. * * @param string $char + * @return void */ private function pushText($char) { @@ -306,10 +321,11 @@ class Document } /** - * Parse control + * Parse control. * * @param string $control * @param string $parameter + * @return void */ private function parseControl($control, $parameter) { @@ -346,9 +362,10 @@ class Document } /** - * Read paragraph + * Read paragraph. * * @param array $directives + * @return void */ private function readParagraph($directives) { @@ -358,9 +375,10 @@ class Document } /** - * Read style + * Read style. * * @param array $directives + * @return void */ private function readStyle($directives) { @@ -369,9 +387,10 @@ class Document } /** - * Read skip + * Read skip. * * @param array $directives + * @return void */ private function readSkip($directives) { @@ -381,7 +400,9 @@ class Document } /** - * Read text + * Read text. + * + * @return void */ private function readText() { diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 70d5f60b..acf40483 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -75,13 +75,14 @@ class Word2007 extends AbstractReader implements ReaderInterface } /** - * Read document part + * Read document part. * * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param array $relationships * @param string $partName * @param string $docFile * @param string $xmlFile + * @return void */ private function readPart(PhpWord &$phpWord, $relationships, $partName, $docFile, $xmlFile) { diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index ac26dee5..0309f193 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -62,7 +62,7 @@ abstract class AbstractPart protected $rels = array(); /** - * Read part + * Read part. */ abstract public function read(PhpWord &$phpWord); @@ -79,9 +79,10 @@ abstract class AbstractPart } /** - * Set relationships + * Set relationships. * * @param array $value + * @return void */ public function setRels($value) { @@ -89,12 +90,13 @@ abstract class AbstractPart } /** - * Read w:p + * Read w:p. * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart + * @return void * * @todo Get font style for preserve text */ @@ -179,13 +181,14 @@ abstract class AbstractPart } /** - * Read w:r + * Read w:r. * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart * @param mixed $paragraphStyle + * @return void * * @todo Footnote paragraph style */ @@ -241,12 +244,13 @@ abstract class AbstractPart } /** - * Read w:tbl + * Read w:tbl. * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart + * @return void */ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart = 'document') { @@ -301,7 +305,7 @@ abstract class AbstractPart } /** - * Read w:pPr + * Read w:pPr. * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode @@ -337,7 +341,7 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @return array + * @return array|null */ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) { diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index e50f295b..d8a8768d 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -52,9 +52,10 @@ class DocPropsCore extends AbstractPart protected $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'); /** - * Read core/extended document properties + * Read core/extended document properties. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 54fe39ee..5f99495e 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -29,9 +29,10 @@ use PhpOffice\PhpWord\Shared\XMLReader; class DocPropsCustom extends AbstractPart { /** - * Read custom document properties + * Read custom document properties. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 02084189..1d51819f 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; -use PhpOffice\PhpWord\Element\Section; /** * Document reader @@ -37,9 +37,10 @@ class Document extends AbstractPart private $phpWord; /** - * Read document.xml + * Read document.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { @@ -61,10 +62,11 @@ class Document extends AbstractPart } /** - * Read header footer + * Read header footer. * * @param array $settings * @param \PhpOffice\PhpWord\Element\Section $section + * @return void */ private function readHeaderFooter($settings, Section &$section) { @@ -138,11 +140,12 @@ class Document extends AbstractPart } /** - * Read w:p node + * Read w:p node. * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section $section + * @return void * * @todo */ @@ -167,11 +170,12 @@ class Document extends AbstractPart } /** - * Read w:sectPr node + * Read w:sectPr node. * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section $section + * @return void */ private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section) { diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 47713cfb..fd351014 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -42,9 +42,10 @@ class Footnotes extends AbstractPart protected $element = 'footnote'; /** - * Read (footnotes|endnotes).xml + * Read (footnotes|endnotes).xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 2dd3f521..bc34bd68 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -28,9 +28,10 @@ use PhpOffice\PhpWord\Shared\XMLReader; class Numbering extends AbstractPart { /** - * Read numbering.xml + * Read numbering.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 7dc4b6ea..00010af6 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -28,9 +28,10 @@ use PhpOffice\PhpWord\Shared\XMLReader; class Styles extends AbstractPart { /** - * Read styles.xml + * Read styles.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ public function read(PhpWord &$phpWord) { diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index cb74389a..8481717b 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -188,7 +188,9 @@ class Settings } /** - * Return the PDF Rendering Library + * Return the PDF Rendering Library. + * + * @return string */ public static function getPdfRendererName() { @@ -214,7 +216,9 @@ class Settings /** - * Return the directory path to the PDF Rendering Library + * Return the directory path to the PDF Rendering Library. + * + * @return string */ public static function getPdfRendererPath() { diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index fc23b5b0..86d466db 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -27,13 +27,14 @@ use PhpOffice\PhpWord\Element\AbstractContainer; class Html { /** - * Add HTML parts + * Add HTML parts. * * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter * * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added * @param string $html The code to parse * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag + * @return void */ public static function addHtml($element, $html, $fullHTML = false) { @@ -88,12 +89,13 @@ class Html } /** - * Parse a node and add a corresponding element to the parent element + * Parse a node and add a corresponding element to the parent element. * * @param \DOMNode $node node to parse * @param \PhpOffice\PhpWord\Element\AbstractContainer $element object to add an element corresponding with the node * @param array $styles Array with all styles * @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems + * @return void */ protected static function parseNode($node, $element, $styles = array(), $data = array()) { @@ -162,12 +164,13 @@ class Html } /** - * Parse child nodes + * Parse child nodes. * * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array $styles * @param array $data + * @return void */ private static function parseChildNodes($node, $element, $styles, $data) { diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 1e4504cc..be04fd0e 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -178,7 +178,9 @@ class String } /** - * Build control characters array + * Build control characters array. + * + * @return void */ private static function buildControlCharacters() { diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 8691ae1d..3d8b8457 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -149,6 +149,7 @@ class XMLWriter * @param string $element * @param string|array $attributes * @param string $value + * @return void */ public function writeElementBlock($element, $attributes, $value = null) { @@ -169,6 +170,7 @@ class XMLWriter * @param string $element * @param string $attribute * @param mixed $value + * @return void */ public function writeElementIf($condition, $element, $attribute = null, $value = null) { @@ -189,6 +191,7 @@ class XMLWriter * @param bool $condition * @param string $attribute * @param mixed $value + * @return void */ public function writeAttributeIf($condition, $attribute, $value) { diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index d56c73fe..73af4f5d 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -123,8 +123,11 @@ class Style } /** - * Reset styles + * Reset styles. + * * @since 0.10.0 + * + * @return void */ public static function resetStyles() { diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 2d1b88d0..11290c87 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -94,7 +94,9 @@ class Cell extends Border private $shading; /** - * Get vertical align + * Get vertical align. + * + * @return string */ public function getVAlign() { @@ -116,7 +118,9 @@ class Cell extends Border } /** - * Get text direction + * Get text direction. + * + * @return string */ public function getTextDirection() { @@ -163,7 +167,9 @@ class Cell extends Border } /** - * Get grid span (colspan) + * Get grid span (colspan). + * + * @return integer */ public function getGridSpan() { @@ -184,7 +190,9 @@ class Cell extends Border } /** - * Get vertical merge (rowspan) + * Get vertical merge (rowspan). + * + * @return string */ public function getVMerge() { diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 9f0a1dde..6220b740 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -67,9 +67,10 @@ class TextBox extends Image private $borderColor; /** - * Set margin top + * Set margin top. * * @param int $value + * @return void */ public function setInnerMarginTop($value = null) { @@ -87,9 +88,10 @@ class TextBox extends Image } /** - * Set margin left + * Set margin left. * * @param int $value + * @return void */ public function setInnerMarginLeft($value = null) { @@ -107,9 +109,10 @@ class TextBox extends Image } /** - * Set margin right + * Set margin right. * * @param int $value + * @return void */ public function setInnerMarginRight($value = null) { @@ -127,9 +130,10 @@ class TextBox extends Image } /** - * Set margin bottom + * Set margin bottom. * * @param int $value + * @return void */ public function setInnerMarginBottom($value = null) { @@ -147,9 +151,10 @@ class TextBox extends Image } /** - * Set TLRB cell margin + * Set TLRB cell margin. * * @param int $value Margin in twips + * @return void */ public function setInnerMargin($value = null) { @@ -188,9 +193,10 @@ class TextBox extends Image } /** - * Set border size + * Set border size. * * @param int $value Size in points + * @return void */ public function setBorderSize($value = null) { @@ -208,9 +214,10 @@ class TextBox extends Image } /** - * Set border color + * Set border color. * * @param string $value + * @return void */ public function setBorderColor($value = null) { diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index fc224d14..2d994574 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -181,6 +181,7 @@ class Template * * @param string $search * @param integer $numberOfClones + * @return void * @throws \PhpOffice\PhpWord\Exception\Exception */ public function cloneRow($search, $numberOfClones) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 8e7cb71d..58ec89b0 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -233,8 +233,9 @@ abstract class AbstractWriter implements WriterInterface } /** - * Cleanup temporary file + * Cleanup temporary file. * + * @return void * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ protected function cleanupTempFile() @@ -253,7 +254,9 @@ abstract class AbstractWriter implements WriterInterface } /** - * Clear temporary directory + * Clear temporary directory. + * + * @return void */ protected function clearTempDir() { @@ -314,11 +317,13 @@ abstract class AbstractWriter implements WriterInterface } /** - * Write content to file + * Write content to file. * - * @param resource $fileHandle - * @param string $content * @since 0.11.0 + * + * @param resource &$fileHandle + * @param string $content + * @return void */ protected function writeFile(&$fileHandle, $content) { @@ -328,10 +333,11 @@ abstract class AbstractWriter implements WriterInterface } /** - * Add files to package + * Add files to package. * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param mixed $elements + * @return void */ protected function addFilesToPackage(ZipArchive $zip, $elements) { @@ -360,13 +366,14 @@ abstract class AbstractWriter implements WriterInterface } /** - * Add file to package + * Add file to package. * - * Get the actual source from an archive image + * Get the actual source from an archive image. * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zipPackage * @param string $source * @param string $target + * @return void */ protected function addFileToPackage($zipPackage, $source, $target) { @@ -394,9 +401,10 @@ abstract class AbstractWriter implements WriterInterface } /** - * Delete directory + * Delete directory. * * @param string $dir + * @return void */ private function deleteDir($dir) { diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 29173ff2..502c50e9 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -61,9 +61,10 @@ class HTML extends AbstractWriter implements WriterInterface } /** - * Save PhpWord to file + * Save PhpWord to file. * * @param string $filename + * @return void * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) @@ -113,10 +114,11 @@ class HTML extends AbstractWriter implements WriterInterface } /** - * Add note + * Add note. * * @param int $noteId * @param string $noteMark + * @return void */ public function addNote($noteId, $noteMark) { diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 53b994df..73f88d3d 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -68,9 +68,10 @@ abstract class AbstractElement } /** - * Set without paragraph + * Set without paragraph. * * @param bool $value + * @return void */ public function setWithoutP($value) { diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 52e7a6b5..c2d4134a 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -81,9 +81,10 @@ class Text extends AbstractElement } /** - * Set opening text + * Set opening text. * * @param string $value + * @return void */ public function setOpeningText($value) { @@ -91,9 +92,10 @@ class Text extends AbstractElement } /** - * Set closing text + * Set closing text. * * @param string $value + * @return void */ public function setClosingText($value) { @@ -164,7 +166,9 @@ class Text extends AbstractElement } /** - * Get font style + * Get font style. + * + * @return void */ private function getFontStyle() { diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 319aa20f..124cc15a 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -42,9 +42,10 @@ abstract class AbstractPart abstract public function write(); /** - * Set parent writer + * Set parent writer. * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * @return void */ public function setParentWriter(AbstractWriter $writer = null) { diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 23e30b8d..4bfe3046 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\HTML\Style\Generic as GenericStyleWriter; use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; @@ -71,6 +71,7 @@ class Head extends AbstractPart return $content; } + /** * Get styles * diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index c729ec55..07ef1618 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -56,9 +56,10 @@ abstract class AbstractStyle } /** - * Set parent writer + * Set parent writer. * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * @return void */ public function setParentWriter($writer) { diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index f9c8d5d4..8fa364be 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -60,9 +60,10 @@ class ODText extends AbstractWriter implements WriterInterface } /** - * Save PhpWord to file + * Save PhpWord to file. * - * @param string $filename + * @param string $filename + * @return void */ public function save($filename = null) { diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 31118ef9..edc8d07f 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -34,7 +34,10 @@ abstract class AbstractPart extends Word2007AbstractPart protected $dateFormat = 'Y-m-d\TH:i:s.000'; /** - * Write common root attributes + * Write common root attributes. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) { @@ -68,7 +71,10 @@ abstract class AbstractPart extends Word2007AbstractPart } /** - * Write font faces declaration + * Write font faces declaration. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ protected function writeFontFaces(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 51326210..b2159d7d 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -23,10 +23,10 @@ use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table as TableStyle; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\ODText\Element\Container; use PhpOffice\PhpWord\Writer\ODText\Style\Paragraph as ParagraphStyleWriter; @@ -106,9 +106,12 @@ class Content extends AbstractPart } /** - * Write automatic styles other than fonts and paragraphs + * Write automatic styles other than fonts and paragraphs. * * @since 0.11.0 + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writeAutoStyles(XMLWriter $xmlWriter) { @@ -129,7 +132,10 @@ class Content extends AbstractPart } /** - * Write automatic styles + * Write automatic styles. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writeTextStyles(XMLWriter $xmlWriter) { @@ -160,7 +166,10 @@ class Content extends AbstractPart } /** - * Get automatic styles + * Get automatic styles. + * + * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return void */ private function getAutoStyles(PhpWord $phpWord) { @@ -183,6 +192,7 @@ class Content extends AbstractPart * @param \PhpOffice\PhpWord\Element\AbstractContainer $container * @param int $paragraphStyleCount * @param int $fontStyleCount + * @return void * @todo Simplify the logic */ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount) @@ -216,6 +226,7 @@ class Content extends AbstractPart * @param \PhpOffice\PhpWord\Element\Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount + * @return void */ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) { diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 9dab2e23..15c81a4e 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -89,6 +89,7 @@ class Meta extends AbstractPart * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $property * @param string $value + * @return void * * @todo Handle other `$type`: double|date|dateTime|duration|boolean (4th arguments) */ diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index b7864fe3..7522872d 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -61,7 +61,10 @@ class Styles extends AbstractPart } /** - * Write default styles + * Write default styles. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writeDefault(XMLWriter $xmlWriter) { @@ -103,7 +106,10 @@ class Styles extends AbstractPart } /** - * Write named styles + * Write named styles. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writeNamed(XMLWriter $xmlWriter) { @@ -122,7 +128,10 @@ class Styles extends AbstractPart } } /** - * Write page layout styles + * Write page layout styles. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writePageLayout(XMLWriter $xmlWriter) { @@ -170,8 +179,12 @@ class Styles extends AbstractPart $xmlWriter->endElement(); // style:page-layout } + /** - * Write master style + * Write master style. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writeMaster(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index acab0ee5..45184505 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; class Font extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index de97f474..21b9c4ee 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; class Image extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 133b8cdf..03e605a1 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; class Paragraph extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index 3d910157..fa432856 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; class Section extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index b32349af..dbfb94ed 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; class Table extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index d4288c8a..572e4b1d 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -190,6 +190,7 @@ abstract class AbstractRenderer extends HTML * Save PhpWord to PDF file, post-save * * @param resource $fileHandle + * @return void * @throws Exception */ protected function restoreStateAfterSave($fileHandle) diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index a40e2cea..47054c4a 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -35,9 +35,10 @@ class DomPDF extends AbstractRenderer implements WriterInterface protected $includeFile = 'dompdf_config.inc.php'; /** - * Save PhpWord to file + * Save PhpWord to file. * * @param string $filename Name of the file to save as + * @return void */ public function save($filename = null) { diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 3fab05c3..46d456d4 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -35,9 +35,10 @@ class MPDF extends AbstractRenderer implements WriterInterface protected $includeFile = 'mpdf.php'; /** - * Save PhpWord to file + * Save PhpWord to file. * * @param string $filename Name of the file to save as + * @return void */ public function save($filename = null) { diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 3d3104de..36849e24 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -35,9 +35,10 @@ class TCPDF extends AbstractRenderer implements WriterInterface protected $includeFile = 'tcpdf.php'; /** - * Save PhpWord to file + * Save PhpWord to file. * * @param string $filename Name of the file to save as + * @return vois */ public function save($filename = null) { diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index d7fed942..a5a58475 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -55,9 +55,10 @@ class RTF extends AbstractWriter implements WriterInterface } /** - * Save content to file + * Save content to file. * * @param string $filename + * @return void * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) @@ -86,7 +87,9 @@ class RTF extends AbstractWriter implements WriterInterface } /** - * Get font table + * Get font table. + * + * @return array */ public function getFontTable() { @@ -94,7 +97,9 @@ class RTF extends AbstractWriter implements WriterInterface } /** - * Get color table + * Get color table. + * + * @return array */ public function getColorTable() { @@ -102,7 +107,9 @@ class RTF extends AbstractWriter implements WriterInterface } /** - * Get last paragraph style + * Get last paragraph style. + * + * @return mixed */ public function getLastParagraphStyle() { @@ -110,9 +117,10 @@ class RTF extends AbstractWriter implements WriterInterface } /** - * Set last paragraph style + * Set last paragraph style. * * @param mixed $value + * @return void */ public function setLastParagraphStyle($value = '') { diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 79e13947..73da5cbd 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -47,7 +47,9 @@ abstract class AbstractElement extends HTMLAbstractElement private $paragraphStyle; /** - * Get font and paragraph styles + * Get font and paragraph styles. + * + * @return void */ protected function getStyles() { diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 68cf1803..574bff76 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -19,8 +19,8 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style; /** * RTF header part writer @@ -52,7 +52,9 @@ class Header extends AbstractPart private $colorTable = array(); /** - * Get font table + * Get font table. + * + * @return array */ public function getFontTable() { @@ -60,7 +62,9 @@ class Header extends AbstractPart } /** - * Get color table + * Get color table. + * + * @return array */ public function getColorTable() { @@ -176,7 +180,9 @@ class Header extends AbstractPart } /** - * Register all fonts and colors in both named and inline styles to appropriate header table + * Register all fonts and colors in both named and inline styles to appropriate header table. + * + * @return void */ private function registerFont() { @@ -204,9 +210,10 @@ class Header extends AbstractPart } /** - * Register border colors + * Register border colors. * * @param \PhpOffice\PhpWord\Style\Border $style + * @return void */ private function registerBorderColor($style) { @@ -219,9 +226,10 @@ class Header extends AbstractPart } /** - * Register fonts and colors + * Register fonts and colors. * * @param \PhpOffice\PhpWord\Style\AbstractStyle $style + * @return void */ private function registerFontItems($style) { @@ -236,11 +244,12 @@ class Header extends AbstractPart } /** - * Register individual font and color + * Register individual font and color. * * @param array $table * @param string $value * @param string $default + * @return void */ private function registerTableItem(&$table, $value, $default = null) { diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 8bb9703f..88c517ad 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -101,9 +101,10 @@ class Border extends AbstractStyle } /** - * Set sizes + * Set sizes. * * @param integer[] $value + * @return void */ public function setSizes($value) { @@ -111,9 +112,10 @@ class Border extends AbstractStyle } /** - * Set colors + * Set colors. * * @param string[] $value + * @return void */ public function setColors($value) { diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 9634b566..20c47aee 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -66,9 +66,11 @@ class Font extends AbstractStyle } /** - * Set font name index + * Set font name index. + * * * @param int $value + * @return void */ public function setNameIndex($value = 0) { @@ -76,9 +78,10 @@ class Font extends AbstractStyle } /** - * Set font color index + * Set font color index. * * @param int $value + * @return void */ public function setColorIndex($value = 0) { diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index b166cc27..1a7de0a3 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -73,9 +73,10 @@ class Paragraph extends AbstractStyle } /** - * Set nested level + * Set nested level. * * @param int $value + * @return void */ public function setNestedLevel($value) { diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index d15f40ac..21471505 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -88,9 +88,10 @@ class Word2007 extends AbstractWriter implements WriterInterface } /** - * Save document by name + * Save document by name. * * @param string $filename + * @return void */ public function save($filename = null) { @@ -163,10 +164,11 @@ class Word2007 extends AbstractWriter implements WriterInterface } /** - * Add header/footer media files, e.g. footer1.xml.rels + * Add header/footer media files, e.g. footer1.xml.rels. * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $docPart + * @return void */ private function addHeaderFooterMedia(ZipArchive $zip, $docPart) { @@ -188,12 +190,13 @@ class Word2007 extends AbstractWriter implements WriterInterface } /** - * Add header/footer content + * Add header/footer content. * * @param \PhpOffice\PhpWord\Element\Section $section * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $elmType header|footer * @param integer $rId + * @return void */ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId) { @@ -220,6 +223,7 @@ class Word2007 extends AbstractWriter implements WriterInterface * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param integer $rId * @param string $noteType + * @return void */ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') { @@ -252,10 +256,11 @@ class Word2007 extends AbstractWriter implements WriterInterface } /** - * Add chart + * Add chart. * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param integer $rId + * @return void */ private function addChart(ZipArchive $zip, &$rId) { @@ -286,9 +291,10 @@ class Word2007 extends AbstractWriter implements WriterInterface } /** - * Register content types for each media + * Register content types for each media. * * @param array $media + * @return void */ private function registerContentTypes($media) { diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index b98b983d..2c200f81 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -89,9 +89,10 @@ abstract class AbstractElement } /** - * Start w:p DOM element + * Start w:p DOM element. * * @uses \PhpOffice\PhpWord\Writer\Word2007\Element\PageBreak::write() + * @return void */ protected function startElementP() { @@ -105,7 +106,9 @@ abstract class AbstractElement } /** - * End w:p DOM element + * End w:p DOM element. + * + * @return void */ protected function endElementP() { @@ -115,7 +118,9 @@ abstract class AbstractElement } /** - * Write ending + * Write ending. + * + * @return void */ protected function writeParagraphStyle() { @@ -123,7 +128,9 @@ abstract class AbstractElement } /** - * Write ending + * Write ending. + * + * @return void */ protected function writeFontStyle() { @@ -132,9 +139,10 @@ abstract class AbstractElement /** - * Write text style + * Write text style. * * @param string $styleType Font|Paragraph + * @return void */ private function writeTextStyle($styleType) { diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index e185ee58..ccd8cd77 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Element\Chart as ChartElement; class Chart extends AbstractElement { /** - * Write element + * Write element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index d5f6a64e..9d060726 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class CheckBox extends Text { /** - * Write element + * Write element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 9504b7a6..771fe5c3 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; +use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; use PhpOffice\PhpWord\Shared\XMLWriter; @@ -37,7 +37,9 @@ class Container extends AbstractElement protected $namespace = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element'; /** - * Write element + * Write element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 7133e83f..b9c3c34b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Field extends Text { /** - * Write field element + * Write field element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index be5a21f1..5640a90d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -32,7 +32,9 @@ class Footnote extends Text protected $referenceType = 'footnoteReference'; /** - * Write element + * Write element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 21003314..432dc9c2 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -35,7 +35,9 @@ class FormField extends Text const FILLER_LENGTH = 30; /** - * Write element + * Write element. + * + * @return void */ public function write() { @@ -102,9 +104,12 @@ class FormField extends Text } /** - * Write textinput + * Write textinput. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\FormField $element + * @return void */ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) { @@ -116,9 +121,12 @@ class FormField extends Text } /** - * Write checkbox + * Write checkbox. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\FormField $element + * @return void */ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) { @@ -137,9 +145,12 @@ class FormField extends Text } /** - * Write dropdown + * Write dropdown. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\FormField $element + * @return void */ private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element) { diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 02780ed1..73988423 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -29,7 +29,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; class Image extends AbstractElement { /** - * Write element + * Write element. + * + * @return void */ public function write() { @@ -47,7 +49,9 @@ class Image extends AbstractElement } /** - * Write image element + * Write image element. + * + * @return void */ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) { @@ -78,8 +82,11 @@ class Image extends AbstractElement $this->endElementP(); } + /** - * Write watermark element + * Write watermark element. + * + * @return void */ private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) { diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index ade5b889..a6c7c240 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Line as LineStyleWriter; class Line extends AbstractElement { /** - * Write element + * Write element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index d7e68ac1..2a5a5ae1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Link extends Text { /** - * Write link element + * Write link element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index 7b86efae..0f559a4e 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; class ListItem extends AbstractElement { /** - * Write list item element + * Write list item element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index 747c2625..289cb054 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; class ListItemRun extends AbstractElement { /** - * Write list item element + * Write list item element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index f172f81b..a9cc449a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; class Object extends AbstractElement { /** - * Write object element + * Write object element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index be317089..fb831ca7 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -25,9 +25,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class PageBreak extends AbstractElement { /** - * Write element + * Write element. * * @usedby \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement::startElementP() + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index ef5b93cd..894b3050 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class PreserveText extends Text { /** - * Write preserve text element + * Write preserve text element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index b41bb696..79d7004d 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -30,7 +30,9 @@ use PhpOffice\PhpWord\Shared\XMLWriter; class SDT extends Text { /** - * Write element + * Write element. + * + * @return void */ public function write() { @@ -68,9 +70,12 @@ class SDT extends Text } /** - * Write combo box + * Write combo box. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\SDT $element + * @return void */ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) { @@ -85,9 +90,12 @@ class SDT extends Text } /** - * Write drop down list + * Write drop down list. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\SDT $element + * @return void */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) { @@ -95,9 +103,12 @@ class SDT extends Text } /** - * Write date + * Write date. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\SDT $element + * @return void */ private function writeDate(XMLWriter $xmlWriter, SDTElement $element) { diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 649e7384..bd9320a2 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Shape as ShapeElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; @@ -31,7 +31,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; class Shape extends AbstractElement { /** - * Write element + * Write element. + * + * @return void */ public function write() { @@ -74,10 +76,11 @@ class Shape extends AbstractElement } /** - * Write arc + * Write arc. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style + * @return void */ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -88,10 +91,11 @@ class Shape extends AbstractElement } /** - * Write curve + * Write curve. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style + * @return void */ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -103,10 +107,11 @@ class Shape extends AbstractElement } /** - * Write line + * Write line. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style + * @return void */ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -117,10 +122,11 @@ class Shape extends AbstractElement } /** - * Write polyline + * Write polyline. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style + * @return void */ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -128,10 +134,11 @@ class Shape extends AbstractElement } /** - * Write rectangle + * Write rectangle. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style + * @return void */ private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style) { diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 1db2efdd..db2a65d0 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -32,7 +32,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Tab as TabStyleWriter; class TOC extends AbstractElement { /** - * Write element + * Write element. + * + * @return void */ public function write() { @@ -68,6 +70,7 @@ class TOC extends AbstractElement * @param \PhpOffice\PhpWord\Element\TOC $element * @param \PhpOffice\PhpWord\Element\Title $title * @param bool $writeFieldMark + * @return void */ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $writeFieldMark) { @@ -135,6 +138,7 @@ class TOC extends AbstractElement * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent + * @return void */ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) { @@ -176,7 +180,11 @@ class TOC extends AbstractElement } /** - * Write TOC Field + * Write TOC Field. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\TOC $element + * @return void */ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element) { diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 8cadfc38..f090d05c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -35,7 +35,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter; class Table extends AbstractElement { /** - * Write element + * Write element. + * + * @return void */ public function write() { @@ -69,7 +71,11 @@ class Table extends AbstractElement } /** - * Write column + * Write column. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Table $element + * @return void */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) { @@ -102,7 +108,11 @@ class Table extends AbstractElement } /** - * Write row + * Write row. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Row $row + * @return void */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) { @@ -125,7 +135,11 @@ class Table extends AbstractElement } /** - * Write cell + * Write cell. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Cell $cell + * @return void */ private function writeCell(XMLWriter $xmlWriter, CellElement $cell) { diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 1fa4861f..cfb991c2 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Text extends AbstractElement { /** - * Write text element + * Write text element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 71935d6e..fe62c644 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\TextBox as TextBoxStyleWriter; class TextBox extends Image { /** - * Write element + * Write element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 83ec2221..fb52b86e 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class TextBreak extends Text { /** - * Write text break element + * Write text break element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index 9ff348cf..844e0b6b 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class TextRun extends Text { /** - * Write textrun element + * Write textrun element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 144e67ab..f48e932a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Title extends AbstractElement { /** - * Write title element + * Write title element. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index 610a7616..e26853d7 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -46,9 +46,10 @@ abstract class AbstractPart abstract public function write(); /** - * Set parent writer + * Set parent writer. * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * @return void */ public function setParentWriter(AbstractWriter $writer = null) { diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 0a0ebac6..8423762c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 chart part writer: word/charts/chartx.xml @@ -59,7 +59,10 @@ class Chart extends AbstractPart private $options = array(); /** - * Set chart element + * Set chart element. + * + * @param \PhpOffice\PhpWord\Element\Chart $element + * @return void */ public function setElement(ChartElement $element) { @@ -93,6 +96,8 @@ class Chart extends AbstractPart * Write chart * * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writeChart(XMLWriter $xmlWriter) { @@ -106,7 +111,7 @@ class Chart extends AbstractPart } /** - * Write plot area + * Write plot area. * * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PlotArea.html * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html @@ -116,6 +121,8 @@ class Chart extends AbstractPart * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @return void */ private function writePlotArea(XMLWriter $xmlWriter) { @@ -171,10 +178,11 @@ class Chart extends AbstractPart } /** - * Write series + * Write series. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $scatter + * @return void */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) { @@ -209,11 +217,12 @@ class Chart extends AbstractPart } /** - * Write series items + * Write series items. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type * @param array $values + * @return void */ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) { @@ -248,9 +257,10 @@ class Chart extends AbstractPart /** * Write axis * + * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html + * @return void */ private function writeAxis(XMLWriter $xmlWriter, $type) { @@ -290,9 +300,10 @@ class Chart extends AbstractPart /** * Write shape * + * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $line - * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html + * @return void */ private function writeShape(XMLWriter $xmlWriter, $line = false) { diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index ac636d3a..6ae4e875 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -82,6 +82,7 @@ class ContentTypes extends AbstractPart * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer * @param array $parts * @param boolean $isDefault + * @return void */ private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault) { diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index e6639511..ea607f09 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -79,10 +79,11 @@ class Document extends AbstractPart } /** - * Write begin section + * Write begin section. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section + * @return void */ private function writeSection(XMLWriter $xmlWriter, Section $section) { @@ -94,10 +95,11 @@ class Document extends AbstractPart } /** - * Write end section + * Write end section. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section + * @return void */ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) { diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 49a47e7d..314cf586 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -26,7 +26,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; class FontTable extends AbstractPart { /** - * Write fontTable.xml + * Write fontTable.xml. + * + * @return string */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 903e5fe5..9ceefd82 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -133,10 +133,11 @@ class Footnotes extends AbstractPart } /** - * Write note item + * Write note item. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Footnote|\PhpOffice\PhpWord\Element\Endnote $element + * @return void */ protected function writeNote(XMLWriter $xmlWriter, $element) { diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 8f735dd3..bbb8eeb4 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Numbering as NumberingStyle; use PhpOffice\PhpWord\Style\NumberingLevel; +use PhpOffice\PhpWord\Style; /** * Word2007 numbering part writer: word/numbering.xml @@ -95,7 +95,11 @@ class Numbering extends AbstractPart } /** - * Write level + * Write level. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\NumberingLevel $level + * @return void */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) { @@ -129,9 +133,13 @@ class Numbering extends AbstractPart } /** - * Write level paragraph + * Write level paragraph. * * @since 0.11.0 + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\NumberingLevel $level + * @return void * @todo Use paragraph style writer */ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) @@ -158,9 +166,13 @@ class Numbering extends AbstractPart } /** - * Write level font + * Write level font. * * @since 0.11.0 + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\NumberingLevel $level + * @return void * @todo Use font style writer */ private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level) diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 562deb35..80ab6307 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -47,12 +47,13 @@ class Rels extends AbstractPart } /** - * Write relationships + * Write relationships. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $xmlRels * @param array $mediaRels * @param int $relId + * @return void */ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRels = array(), $relId = 1) { @@ -74,11 +75,12 @@ class Rels extends AbstractPart } /** - * Write media relationships + * Write media relationships. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId * @param array $mediaRel + * @return void */ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) { @@ -96,7 +98,7 @@ class Rels extends AbstractPart } /** - * Write individual rels entry + * Write individual rels entry. * * Format: * @@ -106,6 +108,7 @@ class Rels extends AbstractPart * @param string $type Relationship type * @param string $target Relationship target * @param string $targetMode Relationship target mode + * @return void * @throws \PhpOffice\PhpWord\Exception\Exception */ private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetMode = '') diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d381d26a..50399c4a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -62,11 +62,12 @@ class Settings extends AbstractPart } /** - * Write indivual setting, recursive to any child settings + * Write indivual setting, recursive to any child settings. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $settingKey * @param array|string $settingValue + * @return void */ protected function writeSetting($xmlWriter, $settingKey, $settingValue) { @@ -90,7 +91,9 @@ class Settings extends AbstractPart } /** - * Get settings + * Get settings. + * + * @return void */ private function getSettings() { @@ -141,7 +144,9 @@ class Settings extends AbstractPart } /** - * Get protection settings + * Get protection settings. + * + * @return void */ private function getProtection() { @@ -157,7 +162,9 @@ class Settings extends AbstractPart } /** - * Get compatibility setting + * Get compatibility setting. + * + * @return void */ private function getCompatibility() { diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 0d688e36..6a8de48a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -19,9 +19,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Settings as PhpWordSettings; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -75,10 +75,11 @@ class Styles extends AbstractPart } /** - * Write default font and other default styles + * Write default font and other default styles. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles + * @return void */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { @@ -139,11 +140,12 @@ class Styles extends AbstractPart } /** - * Write font style + * Write font style. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Font $style + * @return void */ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style) { @@ -192,11 +194,12 @@ class Styles extends AbstractPart } /** - * Write paragraph style + * Write paragraph style. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Paragraph $style + * @return void */ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style) { @@ -224,11 +227,12 @@ class Styles extends AbstractPart } /** - * Write table style + * Write table style. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Table $style + * @return void */ private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style) { diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index d91e37b8..16335680 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -47,7 +47,7 @@ abstract class AbstractStyle abstract public function write(); /** - * Create new instance + * Create new instance. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string|\PhpOffice\PhpWord\Style\AbstractStyle $style @@ -104,11 +104,12 @@ abstract class AbstractStyle } /** - * Write child style + * Write child style. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $name * @param mixed $value + * @return void */ protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value) { diff --git a/src/PhpWord/Writer/Word2007/Style/Alignment.php b/src/PhpWord/Writer/Word2007/Style/Alignment.php index cefadb57..fabaf8ea 100644 --- a/src/PhpWord/Writer/Word2007/Style/Alignment.php +++ b/src/PhpWord/Writer/Word2007/Style/Alignment.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Alignment extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index a4b1ae90..0f90b3aa 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -32,7 +32,9 @@ class Cell extends AbstractStyle private $width; /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -88,9 +90,10 @@ class Cell extends AbstractStyle } /** - * Set width + * Set width. * * @param int $value + * @return void */ public function setWidth($value = null) { diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index aa8ba1ea..ba1ee590 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Extrusion extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index 0695f8ef..645f1ab0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Fill extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 6eb38dc2..67a04829 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -32,7 +32,9 @@ class Font extends AbstractStyle private $isInline = false; /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -51,7 +53,9 @@ class Font extends AbstractStyle } /** - * Write full style + * Write full style. + * + * @return void */ private function writeStyle() { @@ -130,9 +134,10 @@ class Font extends AbstractStyle } /** - * Set is inline + * Set is inline. * * @param bool $value + * @return void */ public function setIsInline($value) { diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 6926081f..2dd61765 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -29,7 +29,9 @@ use PhpOffice\PhpWord\Style\Frame as FrameStyle; class Frame extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -74,7 +76,9 @@ class Frame extends AbstractStyle } /** - * Write alignment + * Write alignment. + * + * @return void */ public function writeAlignment() { @@ -91,11 +95,12 @@ class Frame extends AbstractStyle } /** - * Write alignment + * Write alignment. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style * @param string $wrap + * @return void */ private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap) { diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index f9bb696f..a1b4d8d1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Indentation extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index 8a56cb7b..fd1c21de 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -26,8 +26,9 @@ use PhpOffice\PhpWord\Style\Line as LineStyle; class Line extends Frame { /** - * Write Line stroke + * Write Line stroke. * + * @return void * @todo Merge with `Stroke` style */ public function writeStroke() diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index b3c103b6..d06fa2d6 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class LineNumbering extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void * * The w:start seems to be zero based so we have to decrement by one */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 38dff148..fec987d3 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -48,7 +48,9 @@ class MarginBorder extends AbstractStyle private $attributes = array(); /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -69,12 +71,13 @@ class MarginBorder extends AbstractStyle } /** - * Write side + * Write side. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $side * @param int $width * @param string $color + * @return void */ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null) { @@ -101,9 +104,10 @@ class MarginBorder extends AbstractStyle } /** - * Set sizes + * Set sizes. * * @param integer[] $value + * @return void */ public function setSizes($value) { @@ -111,9 +115,10 @@ class MarginBorder extends AbstractStyle } /** - * Set colors + * Set colors. * * @param string[] $value + * @return void */ public function setColors($value) { @@ -121,9 +126,10 @@ class MarginBorder extends AbstractStyle } /** - * Set attributes + * Set attributes. * * @param array $value + * @return void */ public function setAttributes($value) { diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index e53282a3..06064d18 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Outline extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 86efda2f..039b78bf 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; +use PhpOffice\PhpWord\Style; /** * Paragraph style writer @@ -44,7 +44,9 @@ class Paragraph extends AbstractStyle private $isInline = false; /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -67,7 +69,9 @@ class Paragraph extends AbstractStyle } /** - * Write full style + * Write full style. + * + * @return void */ private function writeStyle() { @@ -126,10 +130,11 @@ class Paragraph extends AbstractStyle } /** - * Write tabs + * Write tabs. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Tab[] $tabs + * @return void */ private function writeTabs(XMLWriter $xmlWriter, $tabs) { @@ -144,10 +149,11 @@ class Paragraph extends AbstractStyle } /** - * Write numbering + * Write numbering. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $numbering + * @return void */ private function writeNumbering(XMLWriter $xmlWriter, $numbering) { @@ -173,9 +179,10 @@ class Paragraph extends AbstractStyle } /** - * Set without w:pPr + * Set without w:pPr. * * @param bool $value + * @return void */ public function setWithoutPPR($value) { @@ -183,9 +190,10 @@ class Paragraph extends AbstractStyle } /** - * Set is inline + * Set is inline. * * @param bool $value + * @return void */ public function setIsInline($value) { diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index 5517cc2b..98841dd8 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -30,7 +30,9 @@ class Row extends AbstractStyle private $height; /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -55,9 +57,10 @@ class Row extends AbstractStyle } /** - * Set height + * Set height. * * @param int $value + * @return void */ public function setHeight($value = null) { diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index fb32a39a..486d0ed2 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Style\Section as SectionStyle; class Section extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 72054c20..8ef8c6b1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Shading extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index dd7c769a..cc746059 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Shadow extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index 7eafb18e..ba8dce5b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Shape extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index 5dfb5c43..2f7e122a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Spacing extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php index 865a5a9c..aa00acc7 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -25,7 +25,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Tab extends AbstractStyle { /** - * Write style + * Write style. + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index e89b121c..8bbad107 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -34,7 +34,9 @@ class Table extends AbstractStyle private $width; /** - * Write style + * Write style. + * + * @return void */ public function write() { @@ -56,7 +58,11 @@ class Table extends AbstractStyle } /** - * Write full style + * Write full style. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Table $style + * @return void */ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) { @@ -83,11 +89,12 @@ class Table extends AbstractStyle } /** - * Write width + * Write width. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $width * @param string $unit + * @return void */ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) { @@ -98,7 +105,11 @@ class Table extends AbstractStyle } /** - * Write margin + * Write margin. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Table $style + * @return void */ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) { @@ -114,7 +125,11 @@ class Table extends AbstractStyle } /** - * Write border + * Write border. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Table $style + * @return void */ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) { @@ -131,7 +146,11 @@ class Table extends AbstractStyle } /** - * Write row style + * Write row style. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Table $style + * @return void */ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) { @@ -147,7 +166,11 @@ class Table extends AbstractStyle } /** - * Write shading + * Write shading. + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Style\Table $style + * @return void */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) { @@ -162,9 +185,10 @@ class Table extends AbstractStyle } /** - * Set width + * Set width. * * @param int $value + * @return void */ public function setWidth($value = null) { diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index a5f82e53..20c68c74 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -27,7 +27,9 @@ use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; class TextBox extends Frame { /** - * Writer inner margin + * Writer inner margin. + * + * @return void */ public function writeInnerMargin() { @@ -43,7 +45,9 @@ class TextBox extends Frame } /** - * Writer border + * Writer border. + * + * @return void */ public function writeBorder() { From 8056b6926c850d7d85db90ecee2ad9dea69d0292 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 3 Jul 2014 16:11:15 +0400 Subject: [PATCH 298/326] [CHANGED] Docblock for pass-by-reference parameters. --- src/PhpWord/Media.php | 2 +- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/RTF/Document.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +++--- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 8 ++++---- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Shared/Html.php | 16 ++++++++-------- src/PhpWord/Style/AbstractStyle.php | 6 +++--- src/PhpWord/Template.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 12 ++++++------ src/PhpWord/Writer/RTF/Part/Header.php | 4 ++-- src/PhpWord/Writer/Word2007.php | 8 ++++---- 19 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 7f35841c..aa289edc 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -38,7 +38,7 @@ class Media * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @param string $source - * @param \PhpOffice\PhpWord\Element\Image $image + * @param \PhpOffice\PhpWord\Element\Image &$image * @return integer * @throws \PhpOffice\PhpWord\Exception\Exception * @since 0.9.2 diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index d7d23c80..0c24185d 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -53,7 +53,7 @@ class ODText extends AbstractReader implements ReaderInterface /** * Read document part. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @param array $relationships * @param string $partName * @param string $docFile diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 9feb669a..aecb7419 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -30,7 +30,7 @@ class Content extends AbstractPart /** * Read content.xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 827446f0..fc061ba1 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -30,7 +30,7 @@ class Meta extends AbstractPart /** * Read meta.xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void * @todo Process property type */ diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 26763576..1f3dbb34 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -129,7 +129,7 @@ class Document * - Builds control words and control symbols * - Pushes every other character into the text queue * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void * @todo Use `fread` stream for scalability */ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index acf40483..556b0bb0 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -77,7 +77,7 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read document part. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @param array $relationships * @param string $partName * @param string $docFile diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 0309f193..eead400f 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -94,7 +94,7 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed $parent + * @param mixed &$parent * @param string $docPart * @return void * @@ -185,7 +185,7 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed $parent + * @param mixed &$parent * @param string $docPart * @param mixed $paragraphStyle * @return void @@ -248,7 +248,7 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed $parent + * @param mixed &$parent * @param string $docPart * @return void */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index d8a8768d..3889db0c 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -54,7 +54,7 @@ class DocPropsCore extends AbstractPart /** * Read core/extended document properties. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 5f99495e..0d81333e 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -31,7 +31,7 @@ class DocPropsCustom extends AbstractPart /** * Read custom document properties. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 1d51819f..afe0e0a5 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -39,7 +39,7 @@ class Document extends AbstractPart /** * Read document.xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) @@ -65,7 +65,7 @@ class Document extends AbstractPart * Read header footer. * * @param array $settings - * @param \PhpOffice\PhpWord\Element\Section $section + * @param \PhpOffice\PhpWord\Element\Section &$section * @return void */ private function readHeaderFooter($settings, Section &$section) @@ -144,7 +144,7 @@ class Document extends AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node - * @param \PhpOffice\PhpWord\Element\Section $section + * @param \PhpOffice\PhpWord\Element\Section &$section * @return void * * @todo @@ -174,7 +174,7 @@ class Document extends AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node - * @param \PhpOffice\PhpWord\Element\Section $section + * @param \PhpOffice\PhpWord\Element\Section &$section * @return void */ private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section) diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index fd351014..30e6c58b 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -44,7 +44,7 @@ class Footnotes extends AbstractPart /** * Read (footnotes|endnotes).xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index bc34bd68..7b33bc4c 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -30,7 +30,7 @@ class Numbering extends AbstractPart /** * Read numbering.xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 00010af6..964147ad 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -30,7 +30,7 @@ class Styles extends AbstractPart /** * Read styles.xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord &$phpWord * @return void */ public function read(PhpWord &$phpWord) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 86d466db..13824f33 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -191,7 +191,7 @@ class Html * * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - * @param array $styles + * @param array &$styles * @return \PhpOffice\PhpWord\Element\TextRun */ private static function parseParagraph($node, $element, &$styles) @@ -206,7 +206,7 @@ class Html * Parse heading node * * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - * @param array $styles + * @param array &$styles * @param string $argument1 Name of heading style * @return \PhpOffice\PhpWord\Element\TextRun * @@ -226,7 +226,7 @@ class Html * * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - * @param array $styles + * @param array &$styles * @return null */ private static function parseText($node, $element, &$styles) @@ -245,7 +245,7 @@ class Html /** * Parse property node * - * @param array $styles + * @param array &$styles * @param string $argument1 Style name * @param string $argument2 Style value * @return null @@ -262,7 +262,7 @@ class Html * * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - * @param array $styles + * @param array &$styles * @param string $argument1 Method name * @return \PhpOffice\PhpWord\Element\AbstractContainer $element * @@ -292,8 +292,8 @@ class Html /** * Parse list node * - * @param array $styles - * @param array $data + * @param array &$styles + * @param array &$data * @param string $argument1 List type * @return null */ @@ -314,7 +314,7 @@ class Html * * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - * @param array $styles + * @param array &$styles * @param array $data * @return null * diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 6f527210..aec490b5 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -297,7 +297,7 @@ abstract class AbstractStyle * * @param mixed $value * @param string $styleName - * @param mixed $style + * @param mixed &$style * @return mixed */ protected function setObjectVal($value, $styleName, &$style) @@ -319,8 +319,8 @@ abstract class AbstractStyle /** * Set $property value and set $pairProperty = false when $value = true * - * @param bool $property - * @param bool $pairProperty + * @param bool &$property + * @param bool &$pairProperty * @param bool $value * @return self */ diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 2d994574..f91e99a2 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -106,7 +106,7 @@ class Template /** * Applies XSL style sheet to template's parts. * - * @param \DOMDocument $xslDOMDocument + * @param \DOMDocument &$xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI * @return void diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index b2159d7d..4bde66ee 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -23,10 +23,10 @@ use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table as TableStyle; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\ODText\Element\Container; use PhpOffice\PhpWord\Writer\ODText\Style\Paragraph as ParagraphStyleWriter; @@ -190,8 +190,8 @@ class Content extends AbstractPart * Table style can be null or string of the style name * * @param \PhpOffice\PhpWord\Element\AbstractContainer $container - * @param int $paragraphStyleCount - * @param int $fontStyleCount + * @param int &$paragraphStyleCount + * @param int &$fontStyleCount * @return void * @todo Simplify the logic */ @@ -223,9 +223,9 @@ class Content extends AbstractPart /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text $element - * @param int $paragraphStyleCount - * @param int $fontStyleCount + * @param \PhpOffice\PhpWord\Element\Text &$element + * @param int &$paragraphStyleCount + * @param int &$fontStyleCount * @return void */ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 574bff76..31fbb7f4 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -19,8 +19,8 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; -use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Font; /** * RTF header part writer @@ -246,7 +246,7 @@ class Header extends AbstractPart /** * Register individual font and color. * - * @param array $table + * @param array &$table * @param string $value * @param string $default * @return void diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 21471505..baac8222 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -192,10 +192,10 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Add header/footer content. * - * @param \PhpOffice\PhpWord\Element\Section $section + * @param \PhpOffice\PhpWord\Element\Section &$section * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $elmType header|footer - * @param integer $rId + * @param integer &$rId * @return void */ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId) @@ -221,7 +221,7 @@ class Word2007 extends AbstractWriter implements WriterInterface * Add footnotes/endnotes * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip - * @param integer $rId + * @param integer &$rId * @param string $noteType * @return void */ @@ -259,7 +259,7 @@ class Word2007 extends AbstractWriter implements WriterInterface * Add chart. * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip - * @param integer $rId + * @param integer &$rId * @return void */ private function addChart(ZipArchive $zip, &$rId) From 4a02142d632ea9a35bab34484647aed454983685 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 12:13:11 +0400 Subject: [PATCH 299/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Element/AbstractElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 82aa543e..4bc6b8e5 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -133,7 +133,7 @@ abstract class AbstractElement */ public function setPhpWord(PhpWord &$phpWord = null) { - $this->phpWord = &$phpWord; + $this->phpWord = $phpWord; } /** From 2c5d13c88e30debc0cb35f60c772c2cf8c124c62 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 12:25:53 +0400 Subject: [PATCH 300/326] [FIXED] Typo in Section->addHeaderFooter(). --- src/PhpWord/Element/Section.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index d746f69b..6377ad49 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -164,7 +164,7 @@ class Section extends AbstractContainer $containerClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . ($header ? 'Header' : 'Footer'); $collectionArray = $header ? 'headers' : 'footers'; - $collection = &$this->$collectionArray; + $collection = &$collectionArray; if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { $index = count($collection); From f2e9e3716b2266e07d6a0b33d9d99fce7c95bde7 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 13:00:52 +0400 Subject: [PATCH 301/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index eead400f..d63a65ad 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -166,15 +166,15 @@ abstract class AbstractPart if ($runLinkCount == 0) { $parent->addTextBreak(null, $paragraphStyle); } else { - if ($runLinkCount > 1) { - $textrun = $parent->addTextRun($paragraphStyle); - $textParent = &$textrun; - } else { - $textParent = &$parent; - } $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $this->readRun($xmlReader, $node, $textParent, $docPart, $paragraphStyle); + $this->readRun( + $xmlReader, + $node, + ($runLinkCount > 1) ? $parent->addTextRun($paragraphStyle) : $parent, + $docPart, + $paragraphStyle + ); } } } From 47a17a33e848acef81075de182330c7b0c674797 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 13:02:28 +0400 Subject: [PATCH 302/326] Revert: [FIXED] Wrong use of passing by reference. --- src/PhpWord/Element/Section.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 6377ad49..d746f69b 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -164,7 +164,7 @@ class Section extends AbstractContainer $containerClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . ($header ? 'Header' : 'Footer'); $collectionArray = $header ? 'headers' : 'footers'; - $collection = &$collectionArray; + $collection = &$this->$collectionArray; if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { $index = count($collection); From 1b9b8d4f90e7cef2cebe6e217c2bd46b04eb8492 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 14:44:22 +0400 Subject: [PATCH 303/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index d63a65ad..efca1962 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -166,15 +166,13 @@ abstract class AbstractPart if ($runLinkCount == 0) { $parent->addTextBreak(null, $paragraphStyle); } else { + $textParent = $parent; + if ($runLinkCount > 1) { + $textParent = &$parent->addTextRun($paragraphStyle); + } $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $this->readRun( - $xmlReader, - $node, - ($runLinkCount > 1) ? $parent->addTextRun($paragraphStyle) : $parent, - $docPart, - $paragraphStyle - ); + $this->readRun($xmlReader, $node, $textParent, $docPart, $paragraphStyle); } } } From d54a674b97a60af84b27f4e2555ad6d3d462e3cd Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 13:07:08 +0200 Subject: [PATCH 304/326] add element bookmark and allow links to internal bookmarks in Word2007 --- src/PhpWord/Element/AbstractContainer.php | 4 +- src/PhpWord/Element/Bookmark.php | 64 +++++++++++++++++++ src/PhpWord/Element/Link.php | 21 +++++- src/PhpWord/PhpWord.php | 11 ++-- .../Writer/Word2007/Element/Bookmark.php | 49 ++++++++++++++ src/PhpWord/Writer/Word2007/Element/Link.php | 10 +-- src/PhpWord/Writer/Word2007/Element/Title.php | 9 ++- 7 files changed, 150 insertions(+), 18 deletions(-) create mode 100644 src/PhpWord/Element/Bookmark.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Bookmark.php diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 686644eb..9b598906 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -22,6 +22,7 @@ namespace PhpOffice\PhpWord\Element; * * @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null) * @method TextRun addTextRun(mixed $pStyle = null) + * @method Bookmark addBookmark(string $name) * @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null) * @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null) * @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null) @@ -78,7 +79,7 @@ abstract class AbstractContainer extends AbstractElement public function __call($function, $args) { $elements = array( - 'Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', + 'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', 'Title', 'TOC', 'PageBreak', @@ -189,6 +190,7 @@ abstract class AbstractContainer extends AbstractElement ); $validContainers = array( 'Text' => $allContainers, + 'Bookmark' => $allContainers, 'Link' => $allContainers, 'TextBreak' => $allContainers, 'Image' => $allContainers, diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php new file mode 100644 index 00000000..39b6d69a --- /dev/null +++ b/src/PhpWord/Element/Bookmark.php @@ -0,0 +1,64 @@ +name = String::toUTF8($name); + return $this; + } + + /** + * Get Bookmark name + * + * @return string + */ + public function getName() + { + return $this->name; + } + +} diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 4b00dc90..81349b5d 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -61,6 +61,13 @@ class Link extends AbstractElement */ protected $mediaRelation = true; + /** + * Has internal flag - anchor to internal bookmark + * + * @var bool + */ + protected $internal = false; + /** * Create a new Link Element * @@ -69,13 +76,13 @@ class Link extends AbstractElement * @param mixed $fontStyle * @param mixed $paragraphStyle */ - public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null) + public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false) { $this->source = String::toUTF8($source); $this->text = is_null($text) ? $this->source : String::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); - + $this->internal = $internal; return $this; } @@ -154,4 +161,14 @@ class Link extends AbstractElement { return $this->getText(); } + + /** + * is internal + * + * @return bool + */ + public function isInternal() + { + return $this->internal; + } } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 3b991e23..93835d91 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -27,6 +27,7 @@ use PhpOffice\PhpWord\Exception\Exception; * @method Collection\Footnotes getFootnotes() * @method Collection\Endnotes getEndnotes() * @method Collection\Charts getCharts() + * @method int addBookmark(Element\Bookmark $bookmark) * @method int addTitle(Element\Title $title) * @method int addFootnote(Element\Footnote $footnote) * @method int addEndnote(Element\Endnote $endnote) @@ -82,7 +83,7 @@ class PhpWord public function __construct() { // Collection - $collections = array('Titles', 'Footnotes', 'Endnotes', 'Charts'); + $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts'); foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); @@ -113,7 +114,7 @@ class PhpWord $addCollection = array(); $addStyle = array(); - $collections = array('Title', 'Footnote', 'Endnote', 'Chart'); + $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart'); foreach ($collections as $collection) { $getCollection[] = strtolower("get{$collection}s"); $addCollection[] = strtolower("add{$collection}"); @@ -218,10 +219,9 @@ class PhpWord } /** - * Set default font name. + * Set default font name * * @param string $fontName - * @return void */ public function setDefaultFontName($fontName) { @@ -239,10 +239,9 @@ class PhpWord } /** - * Set default font size. + * Set default font size * * @param int $fontSize - * @return void */ public function setDefaultFontSize($fontSize) { diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php new file mode 100644 index 00000000..df5a104a --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -0,0 +1,49 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Bookmark) { + return; + } + + $rId = $element->getRelationId(); + + $xmlWriter->startElement('w:bookmarkStart'); + $xmlWriter->writeAttribute('w:id', $rId); + $xmlWriter->writeAttribute('w:name', $element->getName()); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:bookmarkEnd'); + $xmlWriter->writeAttribute('w:id', $rId); + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 2a5a5ae1..31bfa3fd 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -25,9 +25,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Link extends Text { /** - * Write link element. - * - * @return void + * Write link element */ public function write() { @@ -42,7 +40,11 @@ class Link extends Text $this->startElementP(); $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + if($element->isInternal()) { + $xmlWriter->writeAttribute('w:anchor', $element->getSource()); + }else { + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + } $xmlWriter->writeAttribute('w:history', '1'); $xmlWriter->startElement('w:r'); diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index f48e932a..2c2fe0b0 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -25,9 +25,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Title extends AbstractElement { /** - * Write title element. - * - * @return void + * Write title element */ public function write() { @@ -50,10 +48,11 @@ class Title extends AbstractElement } $rId = $element->getRelationId(); + $bookmarkRId = $element->getPhpWord()->addBookmark(); // Bookmark start for TOC $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $rId); + $xmlWriter->writeAttribute('w:id', $bookmarkRId); $xmlWriter->writeAttribute('w:name', "_Toc{$rId}"); $xmlWriter->endElement(); @@ -66,7 +65,7 @@ class Title extends AbstractElement // Bookmark end $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $rId); + $xmlWriter->writeAttribute('w:id', $bookmarkRId); $xmlWriter->endElement(); $xmlWriter->endElement(); From fdeefb77d95eb4d17c355ba42f816e38e48a7585 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 13:24:14 +0200 Subject: [PATCH 305/326] include minor changes from develop branch --- src/PhpWord/PhpWord.php | 6 ++++-- src/PhpWord/Writer/Word2007/Element/Link.php | 2 ++ src/PhpWord/Writer/Word2007/Element/Title.php | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 93835d91..e83ce08f 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -219,9 +219,10 @@ class PhpWord } /** - * Set default font name + * Set default font name. * * @param string $fontName + * @return void */ public function setDefaultFontName($fontName) { @@ -239,9 +240,10 @@ class PhpWord } /** - * Set default font size + * Set default font size. * * @param int $fontSize + * @return void */ public function setDefaultFontSize($fontSize) { diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 31bfa3fd..50f6d131 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -26,6 +26,8 @@ class Link extends Text { /** * Write link element + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 2c2fe0b0..a53af3fa 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -26,6 +26,8 @@ class Title extends AbstractElement { /** * Write title element + * + * @return void */ public function write() { From 475c76dd7907a534dc642dbbbd5400d8bce49e07 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 13:30:07 +0200 Subject: [PATCH 306/326] convert tabs to spaces --- src/PhpWord/PhpWord.php | 4 ++-- src/PhpWord/Writer/Word2007/Element/Link.php | 4 ++-- src/PhpWord/Writer/Word2007/Element/Title.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index e83ce08f..419af4be 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -222,7 +222,7 @@ class PhpWord * Set default font name. * * @param string $fontName - * @return void + * @return void */ public function setDefaultFontName($fontName) { @@ -243,7 +243,7 @@ class PhpWord * Set default font size. * * @param int $fontSize - * @return void + * @return void */ public function setDefaultFontSize($fontSize) { diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 50f6d131..9f53fc7d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -26,8 +26,8 @@ class Link extends Text { /** * Write link element - * - * @return void + * + * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index a53af3fa..abdfc944 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -26,8 +26,8 @@ class Title extends AbstractElement { /** * Write title element - * - * @return void + * + * @return void */ public function write() { From 4d060b3f07f3058e245b07f93ea3965fc674c774 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 13:32:47 +0200 Subject: [PATCH 307/326] sync with develop-branch --- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 9f53fc7d..58156ebc 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -25,7 +25,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Link extends Text { /** - * Write link element + * Write link element. * * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index abdfc944..ce9aeea5 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -25,7 +25,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; class Title extends AbstractElement { /** - * Write title element + * Write title element. * * @return void */ From f2c43291088f2080edfc2ef48b6d94d686d23f10 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 16:00:17 +0400 Subject: [PATCH 308/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index efca1962..90538aec 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -94,13 +94,13 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed &$parent + * @param mixed $parent * @param string $docPart * @return void * * @todo Get font style for preserve text */ - protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart = 'document') + protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document') { // Paragraph style $paragraphStyle = null; @@ -168,7 +168,7 @@ abstract class AbstractPart } else { $textParent = $parent; if ($runLinkCount > 1) { - $textParent = &$parent->addTextRun($paragraphStyle); + $textParent = $parent->addTextRun($paragraphStyle); } $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { @@ -183,14 +183,14 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed &$parent + * @param mixed $parent * @param string $docPart * @param mixed $paragraphStyle * @return void * * @todo Footnote paragraph style */ - protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart, $paragraphStyle = null) + protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart, $paragraphStyle = null) { if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { return; From 87c3df55361bed6204e158de16980d015c5ecbf2 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 14:10:20 +0200 Subject: [PATCH 309/326] add missing file apply formatting to CGL --- src/PhpWord/Collection/Bookmarks.php | 27 ++++++++++++++++++++ src/PhpWord/Element/Bookmark.php | 1 - src/PhpWord/Element/Link.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 8 +++--- 4 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 src/PhpWord/Collection/Bookmarks.php diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php new file mode 100644 index 00000000..cb9d74d5 --- /dev/null +++ b/src/PhpWord/Collection/Bookmarks.php @@ -0,0 +1,27 @@ +name; } - } diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 81349b5d..9d0eb766 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -82,7 +82,7 @@ class Link extends AbstractElement $this->text = is_null($text) ? $this->source : String::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); - $this->internal = $internal; + $this->internal = $internal; return $this; } diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 58156ebc..2cb8407f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -42,10 +42,10 @@ class Link extends Text $this->startElementP(); $xmlWriter->startElement('w:hyperlink'); - if($element->isInternal()) { - $xmlWriter->writeAttribute('w:anchor', $element->getSource()); - }else { - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + if ($element->isInternal()) { + $xmlWriter->writeAttribute('w:anchor', $element->getSource()); + } else { + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); } $xmlWriter->writeAttribute('w:history', '1'); $xmlWriter->startElement('w:r'); From fd209fc999ca3e4fb9b75a1f32375fb80bc4233c Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 16:20:18 +0400 Subject: [PATCH 310/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 90538aec..f5bab011 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -166,13 +166,15 @@ abstract class AbstractPart if ($runLinkCount == 0) { $parent->addTextBreak(null, $paragraphStyle); } else { - $textParent = $parent; - if ($runLinkCount > 1) { - $textParent = $parent->addTextRun($paragraphStyle); - } $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $this->readRun($xmlReader, $node, $textParent, $docPart, $paragraphStyle); + $this->readRun( + $xmlReader, + $node, + ($runLinkCount > 1) ? $parent->addTextRun($paragraphStyle) : $parent, + $docPart, + $paragraphStyle + ); } } } From c4638df0d668de3fd62734f86e257afa4050eec8 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 16:35:13 +0400 Subject: [PATCH 311/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Element/AbstractElement.php | 7 +++---- src/PhpWord/Media.php | 4 ++-- src/PhpWord/Reader/ODText.php | 5 ++--- src/PhpWord/Reader/ODText/Content.php | 4 ++-- src/PhpWord/Reader/ODText/Meta.php | 4 ++-- src/PhpWord/Reader/RTF/Document.php | 4 ++-- src/PhpWord/Reader/Word2007.php | 4 ++-- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 4 ++-- src/PhpWord/Reader/Word2007/DocPropsCustom.php | 4 ++-- src/PhpWord/Reader/Word2007/Document.php | 4 ++-- src/PhpWord/Reader/Word2007/Footnotes.php | 4 ++-- src/PhpWord/Reader/Word2007/Numbering.php | 4 ++-- src/PhpWord/Reader/Word2007/Styles.php | 4 ++-- src/PhpWord/Template.php | 4 ++-- 15 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 4bc6b8e5..4b994a18 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -128,10 +128,10 @@ abstract class AbstractElement /** * Set PhpWord as reference. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function setPhpWord(PhpWord &$phpWord = null) + public function setPhpWord(PhpWord $phpWord) { $this->phpWord = $phpWord; } @@ -285,8 +285,7 @@ abstract class AbstractElement } // Set phpword - $phpWord = $container->getPhpWord(); - $this->setPhpWord($phpWord); + $this->setPhpWord($container->getPhpWord()); // Set doc part if (!$this instanceof Footnote) { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index aa289edc..4bea57ac 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -38,13 +38,13 @@ class Media * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @param string $source - * @param \PhpOffice\PhpWord\Element\Image &$image + * @param \PhpOffice\PhpWord\Element\Image $image * @return integer * @throws \PhpOffice\PhpWord\Exception\Exception * @since 0.9.2 * @since 0.10.0 */ - public static function addElement($container, $mediaType, $source, Image &$image = null) + public static function addElement($container, $mediaType, $source, Image $image = null) { // Assign unique media Id and initiate media container if none exists $mediaId = md5($container . $source); diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 0c24185d..d992f7fd 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -53,14 +53,14 @@ class ODText extends AbstractReader implements ReaderInterface /** * Read document part. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param array $relationships * @param string $partName * @param string $docFile * @param string $xmlFile * @return void */ - private function readPart(PhpWord &$phpWord, $relationships, $partName, $docFile, $xmlFile) + private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile) { $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}"; if (class_exists($partClass)) { @@ -69,7 +69,6 @@ class ODText extends AbstractReader implements ReaderInterface $part->setRels($relationships); $part->read($phpWord); } - } /** diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index aecb7419..cf2fd653 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -30,10 +30,10 @@ class Content extends AbstractPart /** * Read content.xml. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index fc061ba1..d08ce3a6 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -30,11 +30,11 @@ class Meta extends AbstractPart /** * Read meta.xml. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void * @todo Process property type */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 1f3dbb34..fcd9703f 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -129,11 +129,11 @@ class Document * - Builds control words and control symbols * - Pushes every other character into the text queue * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void * @todo Use `fread` stream for scalability */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $markers = array( 123 => 'markOpening', // { diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 556b0bb0..6079567f 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -77,14 +77,14 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read document part. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param array $relationships * @param string $partName * @param string $docFile * @param string $xmlFile * @return void */ - private function readPart(PhpWord &$phpWord, $relationships, $partName, $docFile, $xmlFile) + private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile) { $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}"; if (class_exists($partClass)) { diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index f5bab011..e7155c0b 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -64,7 +64,7 @@ abstract class AbstractPart /** * Read part. */ - abstract public function read(PhpWord &$phpWord); + abstract public function read(PhpWord $phpWord); /** * Create new instance diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 3889db0c..4c48ecbc 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -54,10 +54,10 @@ class DocPropsCore extends AbstractPart /** * Read core/extended document properties. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 0d81333e..eb725b2e 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -31,10 +31,10 @@ class DocPropsCustom extends AbstractPart /** * Read custom document properties. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index afe0e0a5..3ced6763 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -39,10 +39,10 @@ class Document extends AbstractPart /** * Read document.xml. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $this->phpWord = $phpWord; $xmlReader = new XMLReader(); diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 30e6c58b..c66b13fe 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -44,10 +44,10 @@ class Footnotes extends AbstractPart /** * Read (footnotes|endnotes).xml. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $getMethod = "get{$this->collection}"; $collection = $phpWord->$getMethod()->getItems(); diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 7b33bc4c..872d4503 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -30,10 +30,10 @@ class Numbering extends AbstractPart /** * Read numbering.xml. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $abstracts = array(); $numberings = array(); diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 964147ad..299fe1df 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -30,10 +30,10 @@ class Styles extends AbstractPart /** * Read styles.xml. * - * @param \PhpOffice\PhpWord\PhpWord &$phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function read(PhpWord &$phpWord) + public function read(PhpWord $phpWord) { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index f91e99a2..28055cea 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -106,13 +106,13 @@ class Template /** * Applies XSL style sheet to template's parts. * - * @param \DOMDocument &$xslDOMDocument + * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI * @return void * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') + public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') { $processor = new \XSLTProcessor(); From 7bbe1ed620de8b9835171818953c5b04342ddd36 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 16:49:01 +0400 Subject: [PATCH 312/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 4 ++-- src/PhpWord/Writer/AbstractWriter.php | 4 ++-- src/PhpWord/Writer/HTML.php | 3 +-- src/PhpWord/Writer/RTF.php | 3 +-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index e7155c0b..8a409379 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -248,11 +248,11 @@ abstract class AbstractPart * * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed &$parent + * @param mixed $parent * @param string $docPart * @return void */ - protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart = 'document') + protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document') { // Table style $tblStyle = null; diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 58ec89b0..52a2098f 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -321,11 +321,11 @@ abstract class AbstractWriter implements WriterInterface * * @since 0.11.0 * - * @param resource &$fileHandle + * @param resource $fileHandle * @param string $content * @return void */ - protected function writeFile(&$fileHandle, $content) + protected function writeFile($fileHandle, $content) { fwrite($fileHandle, $content); fclose($fileHandle); diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 502c50e9..5c58acfc 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -69,8 +69,7 @@ class HTML extends AbstractWriter implements WriterInterface */ public function save($filename = null) { - $fileHandle = $this->openFile($filename); - $this->writeFile($fileHandle, $this->getContent()); + $this->writeFile($this->openFile($filename), $this->getContent()); } /** diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index a5a58475..58210c99 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -63,8 +63,7 @@ class RTF extends AbstractWriter implements WriterInterface */ public function save($filename = null) { - $fileHandle = $this->openFile($filename); - $this->writeFile($fileHandle, $this->getContent()); + $this->writeFile($this->openFile($filename), $this->getContent()); } /** From 197c6ec0b380ba0bae640a876455198e6826db4b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 4 Jul 2014 16:52:39 +0400 Subject: [PATCH 313/326] [FIXED] Wrong use of passing by reference. --- src/PhpWord/Element/AbstractElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 4b994a18..99a7a1be 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -131,7 +131,7 @@ abstract class AbstractElement * @param \PhpOffice\PhpWord\PhpWord $phpWord * @return void */ - public function setPhpWord(PhpWord $phpWord) + public function setPhpWord(PhpWord $phpWord = null) { $this->phpWord = $phpWord; } From 7c8ff2884bcbd0e075929e221580d3e266d97a29 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 15:31:48 +0200 Subject: [PATCH 314/326] add sample fix undefined Index --- samples/Sample_35_InternalLink.php | 22 ++++++++++++++++++++++ src/PhpWord/PhpWord.php | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 samples/Sample_35_InternalLink.php diff --git a/samples/Sample_35_InternalLink.php b/samples/Sample_35_InternalLink.php new file mode 100644 index 00000000..3b6aae51 --- /dev/null +++ b/samples/Sample_35_InternalLink.php @@ -0,0 +1,22 @@ +addSection(); +$section->addTitle( 'This is page 1', 1 ); +$linkIsInternal = true; +$section->addLink('MyBookmark', 'Take me to page 3', null ,null,$linkIsInternal); +$section->addPageBreak(); +$section->addTitle( 'This is page 2', 1 ); +$section->addPageBreak(); +$section->addTitle( 'This is page 3', 1 ); +$section->addBookmark('MyBookmark'); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 419af4be..cde4351e 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -139,7 +139,7 @@ class PhpWord /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collectionObject */ $collectionObject = $this->collections[$key]; - return $collectionObject->addItem($args[0]); + return $collectionObject->addItem(array_key_exists(0,$args) ? $args[0] : null); } // Run add style method From 6c9cffd83b8d40ebf82663722389f596d3b5c945 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 15:40:48 +0200 Subject: [PATCH 315/326] updated documentation for link-Element. added documentation for bookmark-Element. --- docs/elements.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index 2f2fb91c..46db6e40 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -53,6 +53,8 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 22 | Form fields | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 23 | Bookmarks | v | - | - | v | v | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -129,12 +131,13 @@ You can add Hyperlinks to the document by using the function addLink: .. code-block:: php - $section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]); + $section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle], [$isInternal]); - ``$linkSrc`` The URL of the link. - ``$linkName`` Placeholder of the URL that appears in the document. - ``$fontStyle`` See "Font style" section. - ``$paragraphStyle`` See "Paragraph style" section. +- ``$isInternal`` Set to true, if the link points to a bookmark inside the document Preserve texts ~~~~~~~~~~~~~~ @@ -429,3 +432,14 @@ Form fields ----------- To be completed. + +Bookmarks +~~~~~ + +You can add Bookmarks to the document by using the function addBookmark: + +.. code-block:: php + + $section->addBookmark($name); + +- ``$name`` The name of the bookmark which can be referenced in the addLink-Function as target. Should obviously be unique throughout the document. \ No newline at end of file From 72026345730a0548b55664ebe218a8398cd8ad92 Mon Sep 17 00:00:00 2001 From: jogo Date: Fri, 4 Jul 2014 15:54:20 +0200 Subject: [PATCH 316/326] fix wrong formatting --- src/PhpWord/PhpWord.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index cde4351e..083f9d37 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -139,7 +139,7 @@ class PhpWord /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collectionObject */ $collectionObject = $this->collections[$key]; - return $collectionObject->addItem(array_key_exists(0,$args) ? $args[0] : null); + return $collectionObject->addItem(array_key_exists(0, $args) ? $args[0] : null); } // Run add style method From 61406af166c7c049fb5ddb146e3f43562e6380f9 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 9 Jul 2014 08:51:18 +0200 Subject: [PATCH 317/326] FIXED : #292 : Update elements.rst --- CHANGELOG.md | 1 + docs/elements.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1ac091e..44bf46db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap ### Miscellaneous - Docs: Add known issue on `README` about requirement for temporary folder to be writable and update `samples/index.php` for this requirement check - @ivanlanin GH-238 +- Docs: Correct elements.rst about Line - @chrissharkman GH-292 - PclZip: Remove temporary file after used - @andrew-kzoo GH-265 - Autoloader: Add the ability to set the autoloader options - @bskrtich GH-267 - Element: Refactor elements to move set relation Id from container to element - @ivanlanin diff --git a/docs/elements.rst b/docs/elements.rst index 46db6e40..eae23c9d 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -404,13 +404,13 @@ Line elements can be added to sections by using ``addLine``. .. code-block:: php - $linestyle = array('weight' => 1, 'width' => 100, 'height' => 0, 'color' => 635552); + $linestyle = array('weight' => 1, 'width' => 100, 'height' => 0, 'color' => '#b2a68b'); $section->addLine($lineStyle) Available line style attributes: - ``weight`` Line width in twips -- ``color`` Defines the color of stroke +- ``color`` Defines the color of stroke. The hex value must be introduced with #. - ``dash`` Line types: dash, rounddot, squaredot, dashdot, longdash, longdashdot, longdashdotdot - ``beginArrow`` Start type of arrow: block, open, classic, diamond, oval - ``endArrow`` End type of arrow: block, open, classic, diamond, ovel From 07e03fc955ca39bb96647e8365c99d7ad73dd926 Mon Sep 17 00:00:00 2001 From: Philipp Scheit Date: Tue, 15 Jul 2014 10:24:36 +0200 Subject: [PATCH 318/326] bugfix: specific borders were not written correctly in word2007 --- CHANGELOG.md | 1 + src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44bf46db..4cb0a086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Page breaks on titles and tables - @ivanlanin GH-274 - Table inside vertical border does not rendered properly - @ivanlanin GH-280 - `add` of container should be case insensitive, e.g. `addToc` should be accepted, not only `addTOC` - @ivanlanin GH-294 +- Fix specific borders (and margins) were not written correctly in word2007 writer ### Deprecated diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index fec987d3..ace1e1ac 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -59,8 +59,8 @@ class MarginBorder extends AbstractStyle $sides = array('top', 'left', 'right', 'bottom', 'insideH', 'insideV'); $sizeCount = count($this->sizes); - for ($i = 0; $i < $sizeCount; $i++) { - if ($this->sizes[$i] !== null) { + foreach ($this->sizes as $i => $size) { + if ($size !== null) { $color = null; if (isset($this->colors[$i])) { $color = $this->colors[$i]; From 06005e335d612f87dbaa37c150021a7631788a28 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 4 Aug 2014 10:50:51 +0200 Subject: [PATCH 319/326] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb0a086..09ba8668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Page breaks on titles and tables - @ivanlanin GH-274 - Table inside vertical border does not rendered properly - @ivanlanin GH-280 - `add` of container should be case insensitive, e.g. `addToc` should be accepted, not only `addTOC` - @ivanlanin GH-294 -- Fix specific borders (and margins) were not written correctly in word2007 writer +- Fix specific borders (and margins) were not written correctly in word2007 writer - @pscheit GH-327 ### Deprecated From f25833c60d554b4ca73985cd28c721fe3348b154 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 4 Aug 2014 11:17:05 +0200 Subject: [PATCH 320/326] #327 : Fixes PHP-MD errors @link : https://travis-ci.org/PHPOffice/PHPWord/jobs/31598319#L539 --- src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index ace1e1ac..fb4afede 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -57,7 +57,6 @@ class MarginBorder extends AbstractStyle $xmlWriter = $this->getXmlWriter(); $sides = array('top', 'left', 'right', 'bottom', 'insideH', 'insideV'); - $sizeCount = count($this->sizes); foreach ($this->sizes as $i => $size) { if ($size !== null) { From 56c3d8eda294d787af1602e4ca7227c3fed0ecbb Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 10 Aug 2014 20:00:19 +0400 Subject: [PATCH 321/326] https://github.com/PHPOffice/PHPWord/issues/310 --- CHANGELOG.md | 1 + phpword.ini.dist | 1 + samples/index.php | 2 +- src/PhpWord/Element/Image.php | 7 ++-- src/PhpWord/Settings.php | 36 +++++++++++++++++++ src/PhpWord/Shared/ZipArchive.php | 4 +-- src/PhpWord/Template.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 5 +-- tests/PhpWord/Tests/SettingsTest.php | 26 ++++++++++++++ tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php | 4 +-- .../Tests/_includes/TestHelperDOCX.php | 15 ++++---- 11 files changed, 85 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ba8668..e7564f68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Autoloader: Add the ability to set the autoloader options - @bskrtich GH-267 - Element: Refactor elements to move set relation Id from container to element - @ivanlanin - Introduced CreateTemporaryFileException, CopyFileException - @RomanSyroeshko +- Settings: added method to set user defined temporary directory - @RomanSyroeshko GH-310 ## 0.11.1 - 2 June 2014 diff --git a/phpword.ini.dist b/phpword.ini.dist index 4a51ee11..f8eafb6a 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -7,6 +7,7 @@ compatibility = true zipClass = ZipArchive pdfRendererName = DomPDF pdfRendererPath = +; tempDir = "C:\PhpWordTemp" [Font] diff --git a/samples/index.php b/samples/index.php index 5632664f..4281f6fb 100644 --- a/samples/index.php +++ b/samples/index.php @@ -3,7 +3,7 @@ include_once 'Sample_Header.php'; $requirements = array( 'php' => array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), 'xml' => array('PHP extension XML', extension_loaded('xml')), - 'temp' => array('Temp folder "' . sys_get_temp_dir() . '" is writable', is_writable(sys_get_temp_dir())), + 'temp' => array('Temp folder "' . Settings::getTempDir() . '" is writable', is_writable(Settings::getTempDir())), 'zip' => array('PHP extension ZipArchive (optional)', extension_loaded('zip')), 'gd' => array('PHP extension GD (optional)', extension_loaded('gd')), 'xmlw' => array('PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')), diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index e48f703e..4a812f6c 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Style\Image as ImageStyle; @@ -313,8 +314,8 @@ class Image extends AbstractElement if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $isTemp = true; - $zip->extractTo(sys_get_temp_dir(), $imageFilename); - $actualSource = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $imageFilename; + $zip->extractTo(Settings::getTempDir(), $imageFilename); + $actualSource = Settings::getTempDir() . DIRECTORY_SEPARATOR . $imageFilename; } } $zip->close(); @@ -428,7 +429,7 @@ class Image extends AbstractElement $imageData = null; $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); - $tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage'); + $tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage'); $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 8481717b..009c849c 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -119,6 +119,13 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** + * The user defined temporary directory. + * + * @var string + */ + private static $tempDir = ''; + /** * Return the compatibility option used by the XMLWriter * @@ -269,6 +276,35 @@ class Settings return true; } + /** + * Sets the user defined path to temporary directory. + * + * @param string $tempDir The user defined path to temporary directory. + * @return void + * @since 0.12.0 + */ + public static function setTempDir($tempDir) + { + self::$tempDir = $tempDir; + } + + /** + * Returns path to temporary directory. + * + * @return string + * @since 0.12.0 + */ + public static function getTempDir() + { + $tempDir = sys_get_temp_dir(); + + if (!empty(self::$tempDir)) { + $tempDir = self::$tempDir; + } + + return $tempDir; + } + /** * Get default font name * diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 7515c5b5..38781a80 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -83,7 +83,7 @@ class ZipArchive $this->usePclzip = (Settings::getZipClass() != 'ZipArchive'); if ($this->usePclzip) { if (!defined('PCLZIP_TEMPORARY_DIR')) { - define('PCLZIP_TEMPORARY_DIR', sys_get_temp_dir() . '/'); + define('PCLZIP_TEMPORARY_DIR', Settings::getTempDir() . '/'); } require_once 'PCLZip/pclzip.lib.php'; } @@ -139,7 +139,7 @@ class ZipArchive $this->numFiles = $zip->numFiles; } else { $zip = new \PclZip($this->filename); - $this->tempDir = sys_get_temp_dir(); + $this->tempDir = Settings::getTempDir(); $this->numFiles = count($zip->listContent()); } $this->zip = $zip; diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 28055cea..c8f88026 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -67,7 +67,7 @@ class Template */ public function __construct($fileName) { - $this->tempFileName = tempnam(sys_get_temp_dir(), ''); + $this->tempFileName = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $this->tempFileName) { throw new CreateTemporaryFileException(); } diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 52a2098f..c74819b5 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -20,6 +20,7 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\ZipArchive; /** @@ -214,12 +215,12 @@ abstract class AbstractWriter implements WriterInterface protected function getTempFile($filename) { // Temporary directory - $this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/'); + $this->setTempDir(Settings::getTempDir() . '/PHPWordWriter/'); // Temporary file $this->originalFilename = $filename; if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { - $filename = @tempnam(sys_get_temp_dir(), 'phpword_'); + $filename = tempnam(Settings::getTempDir(), 'phpword_'); // @codeCoverageIgnoreStart // Can't find any test case. Uncomment when found. if ($filename == '') { diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index 61364034..0d3d66ae 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Settings; /** * Test class for PhpOffice\PhpWord\Settings * + * @coversDefaultClass \PhpOffice\PhpWord\Settings * @runTestsInSeparateProcesses */ class SettingsTest extends \PHPUnit_Framework_TestCase @@ -70,6 +71,31 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertFalse(Settings::setMeasurementUnit('foo')); } + /** + * @covers ::getTempDir + * @test + */ + public function testPhpTempDirIsUsedByDefault() + { + $this->assertEquals(sys_get_temp_dir(), Settings::getTempDir()); + } + + + /** + * @covers ::setTempDir + * @covers ::getTempDir + * @depends testPhpTempDirIsUsedByDefault + * @test + */ + public function testTempDirCanBeSet() + { + $userDefinedTempDir = 'C:\PhpWordTemp'; + Settings::setTempDir($userDefinedTempDir); + $currentTempDir = Settings::getTempDir(); + $this->assertEquals($userDefinedTempDir, $currentTempDir); + $this->assertNotEquals(sys_get_temp_dir(), $currentTempDir); + } + /** * Test set/get default font name */ diff --git a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php index a22cb530..476c9011 100644 --- a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php @@ -71,7 +71,7 @@ class DomPDFTest extends \PHPUnit_Framework_TestCase $writer->setOrientation(); $this->assertEquals('default', $writer->getOrientation()); - $writer->setTempDir(sys_get_temp_dir()); - $this->assertEquals(sys_get_temp_dir(), $writer->getTempDir()); + $writer->setTempDir(Settings::getTempDir()); + $this->assertEquals(Settings::getTempDir(), $writer->getTempDir()); } } diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 7998cbdc..553a51be 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; /** * Test helper class @@ -41,9 +42,9 @@ class TestHelperDOCX */ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') { - self::$file = tempnam(sys_get_temp_dir(), 'PhpWord'); - if (!is_dir(sys_get_temp_dir() . '/PhpWord_Unit_Test/')) { - mkdir(sys_get_temp_dir() . '/PhpWord_Unit_Test/'); + self::$file = tempnam(Settings::getTempDir(), 'PhpWord'); + if (!is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) { + mkdir(Settings::getTempDir() . '/PhpWord_Unit_Test/'); } $xmlWriter = IOFactory::createWriter($phpWord, $writerName); @@ -52,11 +53,11 @@ class TestHelperDOCX $zip = new \ZipArchive; $res = $zip->open(self::$file); if ($res === true) { - $zip->extractTo(sys_get_temp_dir() . '/PhpWord_Unit_Test/'); + $zip->extractTo(Settings::getTempDir() . '/PhpWord_Unit_Test/'); $zip->close(); } - return new XmlDocument(sys_get_temp_dir() . '/PhpWord_Unit_Test/'); + return new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); } /** @@ -67,8 +68,8 @@ class TestHelperDOCX if (file_exists(self::$file)) { unlink(self::$file); } - if (is_dir(sys_get_temp_dir() . '/PhpWord_Unit_Test/')) { - self::deleteDir(sys_get_temp_dir() . '/PhpWord_Unit_Test/'); + if (is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) { + self::deleteDir(Settings::getTempDir() . '/PhpWord_Unit_Test/'); } } From e6d88a27e881c318a8435d0b254a7ba2cd2e4275 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 10 Aug 2014 20:30:14 +0400 Subject: [PATCH 322/326] Refactored usages of "tempnam()" function. --- src/PhpWord/Element/Image.php | 8 +++++++- src/PhpWord/Shared/XMLWriter.php | 4 ++-- src/PhpWord/Writer/AbstractWriter.php | 7 ++----- tests/PhpWord/Tests/_includes/TestHelperDOCX.php | 6 ++++++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 4a812f6c..ab350e07 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; use PhpOffice\PhpWord\Settings; @@ -423,13 +424,18 @@ class Image extends AbstractElement * * @param string $source * @return array|null + * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException */ private function getArchiveImageSize($source) { $imageData = null; $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); + $tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage'); + if (false === $tempFilename) { + throw new CreateTemporaryFileException(); + } $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { @@ -437,7 +443,7 @@ class Image extends AbstractElement $imageContent = $zip->getFromName($imageFilename); if ($imageContent !== false) { file_put_contents($tempFilename, $imageContent); - $imageData = @getimagesize($tempFilename); + $imageData = getimagesize($tempFilename); unlink($tempFilename); } } diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 3d8b8457..2134f62a 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -66,12 +66,12 @@ class XMLWriter $this->xmlWriter->openMemory(); } else { // Create temporary filename - $this->tempFile = @tempnam($tempFolder, 'xml'); + $this->tempFile = tempnam($tempFolder, 'xml'); // Fallback to memory when temporary file cannot be used // @codeCoverageIgnoreStart // Can't find any test case. Uncomment when found. - if ($this->xmlWriter->openUri($this->tempFile) === false) { + if (false === $this->tempFile || false === $this->xmlWriter->openUri($this->tempFile)) { $this->xmlWriter->openMemory(); } // @codeCoverageIgnoreEnd diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index c74819b5..31097b89 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -220,13 +220,10 @@ abstract class AbstractWriter implements WriterInterface // Temporary file $this->originalFilename = $filename; if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { - $filename = tempnam(Settings::getTempDir(), 'phpword_'); - // @codeCoverageIgnoreStart - // Can't find any test case. Uncomment when found. - if ($filename == '') { + $filename = tempnam(Settings::getTempDir(), 'PhpWord'); + if (false === $filename) { $filename = $this->originalFilename; } - // @codeCoverageIgnoreEnd } $this->tempFilename = $filename; diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 553a51be..6ca6a14d 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests; +use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; @@ -39,10 +40,15 @@ class TestHelperDOCX * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $writerName * @return \PhpOffice\PhpWord\Tests\XmlDocument + * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException */ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') { self::$file = tempnam(Settings::getTempDir(), 'PhpWord'); + if (false === self::$file) { + throw new CreateTemporaryFileException(); + } + if (!is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) { mkdir(Settings::getTempDir() . '/PhpWord_Unit_Test/'); } From e31f080ea6149a309e73c31acba4efe47eab9e31 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 10 Aug 2014 20:46:10 +0400 Subject: [PATCH 323/326] Removed unused comment. --- src/PhpWord/PhpWord.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 083f9d37..84e5ebc7 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -297,7 +297,6 @@ class PhpWord 'PDF' => 'application/pdf', ); - /** @var \PhpOffice\PhpWord\Writer\WriterInterface $writer */ $writer = IOFactory::createWriter($this, $format); if ($download === true) { From 3d06c77fc1a49d04555ce240ba64bc06383adc10 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 10 Aug 2014 21:01:46 +0400 Subject: [PATCH 324/326] Minor refactoring of "Shared\ZipArchive" class. --- src/PhpWord/Shared/ZipArchive.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 38781a80..157959e8 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -158,7 +158,7 @@ class ZipArchive { if (!$this->usePclzip) { if ($this->zip->close() === false) { - throw new Exception("Could not close zip file $this->filename."); + throw new Exception("Could not close zip file {$this->filename}."); } } @@ -233,7 +233,7 @@ class ZipArchive $tempFile = false; if ($filenameParts['basename'] != $localnameParts['basename']) { $tempFile = true; // temp file created - $temppath = $this->tempDir . '/' . $localnameParts['basename']; + $temppath = $this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']; copy($filename, $temppath); $filename = $temppath; $filenameParts = pathinfo($temppath); @@ -246,7 +246,7 @@ class ZipArchive if ($tempFile) { // Remove temp file, if created - @unlink($this->tempDir . '/' . $localnameParts["basename"]); + unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']); } return ($res == 0) ? false : true; @@ -266,19 +266,19 @@ class ZipArchive $filenameParts = pathinfo($localname); // Write $contents to a temp file - $handle = fopen($this->tempDir . '/' . $filenameParts["basename"], "wb"); + $handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'], 'wb'); fwrite($handle, $contents); fclose($handle); // Add temp file to zip - $filename = $this->tempDir . '/' . $filenameParts["basename"]; + $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']; $pathRemoved = $this->tempDir; $pathAdded = $filenameParts['dirname']; $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); // Remove temp file - @unlink($this->tempDir . '/' . $filenameParts["basename"]); + @unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']); return ($res == 0) ? false : true; } @@ -338,7 +338,7 @@ class ZipArchive $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); } if ((is_array($extracted)) && ($extracted != 0)) { - $contents = $extracted[0]["content"]; + $contents = $extracted[0]['content']; } return $contents; @@ -377,8 +377,8 @@ class ZipArchive $listCount = count($list); $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($filename) || - strtolower($list[$i]["stored_filename"]) == strtolower($filename)) { + if (strtolower($list[$i]['filename']) == strtolower($filename) || + strtolower($list[$i]['stored_filename']) == strtolower($filename)) { $listIndex = $i; break; } From 6f2d444ba9dd97a2c2fb18b3022e3fefa46a64bc Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Mon, 11 Aug 2014 22:30:46 +0400 Subject: [PATCH 325/326] https://github.com/PHPOffice/PHPWord/issues/310 --- src/PhpWord/Element/Image.php | 2 ++ src/PhpWord/Settings.php | 6 ++++-- tests/PhpWord/Tests/_includes/TestHelperDOCX.php | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index ab350e07..cab2527a 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -422,6 +422,8 @@ class Image extends AbstractElement /** * Get image size from archive * + * @since 0.12.0 Throws CreateTemporaryFileException. + * * @param string $source * @return array|null * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 009c849c..6c7f17e1 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -279,9 +279,10 @@ class Settings /** * Sets the user defined path to temporary directory. * + * @since 0.12.0 + * * @param string $tempDir The user defined path to temporary directory. * @return void - * @since 0.12.0 */ public static function setTempDir($tempDir) { @@ -291,8 +292,9 @@ class Settings /** * Returns path to temporary directory. * - * @return string * @since 0.12.0 + * + * @return string */ public static function getTempDir() { diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 6ca6a14d..2a0043d5 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -37,6 +37,8 @@ class TestHelperDOCX /** * Get document content * + * @since 0.12.0 Throws CreateTemporaryFileException. + * * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $writerName * @return \PhpOffice\PhpWord\Tests\XmlDocument From 8d9e85b2ba21752c1cbfe7b7a48b14e4b54bfa03 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 12 Aug 2014 13:32:05 +0200 Subject: [PATCH 326/326] #331 : Word2007 Writer : Support for RTL --- .gitignore | 1 + CHANGELOG.md | 1 + docs/intro.rst | 1 + docs/styles.rst | 1 + samples/Sample_36_RTL.php | 19 +++++++ samples/index.php | 2 + src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Style/Font.php | 30 +++++++++++ src/PhpWord/Writer/Word2007/Style/Font.php | 6 +++ .../Tests/Writer/Word2007/Style/FontTest.php | 54 +++++++++++++++++++ 10 files changed, 116 insertions(+) create mode 100644 samples/Sample_36_RTL.php create mode 100644 tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php diff --git a/.gitignore b/.gitignore index 810a7b0a..a74da9de 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ phpword.ini /.settings /build /vendor +/phpunit.bat diff --git a/CHANGELOG.md b/CHANGELOG.md index e7564f68..6040c46e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Setting: Ability to remove [Compatibility Mode] text in the MS Word title bar - @ivanlanin - SDT: Ability to add structured document tag elements (comboBox, dropDownList, date) - @ivanlanin - Paragraph: Support for paragraph with borders - @ivanlanin GH-294 +- Word2007 Writer : Support for RTL - @Progi1984 GH-331 ### Bugfixes diff --git a/docs/intro.rst b/docs/intro.rst index b604298f..03821c91 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -37,6 +37,7 @@ Features run) that contains other elements - Insert titles (headers) and table of contents - Insert text breaks and page breaks +- Insert right-to-left text - Insert and format images, either local, remote, or as page watermarks - Insert binary OLE Objects such as Excel or Visio - Insert and format table with customized properties for each rows diff --git a/docs/styles.rst b/docs/styles.rst index cd07a9f7..91d5ed7a 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -56,6 +56,7 @@ Available font styles: - ``bgColor`` Font background color, e.g. *FF0000* - ``smallCaps`` Small caps, *true* or *false* - ``allCaps`` All caps, *true* or *false* +- ``rtl`` Right to Left language, *true* or *false* Paragraph --------- diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php new file mode 100644 index 00000000..9b85fb1e --- /dev/null +++ b/samples/Sample_36_RTL.php @@ -0,0 +1,19 @@ +addSection(); +$textrun = $section->addTextRun(); +$textrun->addText('This is a Left to Right paragraph.'); + +$textrun = $section->addTextRun(array('align' => 'right')); +$textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/index.php b/samples/index.php index 4281f6fb..f25f7f33 100644 --- a/samples/index.php +++ b/samples/index.php @@ -1,5 +1,7 @@ array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), 'xml' => array('PHP extension XML', extension_loaded('xml')), diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 8a409379..7d3e0f66 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -373,6 +373,7 @@ abstract class AbstractPart 'superScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'superscript'), 'subScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'), 'fgColor' => array(self::READ_VALUE, 'w:highlight'), + 'rtl' => array(self::READ_TRUE, 'w:rtl'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 000e2bb6..8980258b 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -222,6 +222,12 @@ class Font extends AbstractStyle */ private $shading; + /** + * Right to left languages + * @var boolean + */ + private $rtl = false; + /** * Create new font style * @@ -268,6 +274,7 @@ class Font extends AbstractStyle 'kerning' => $this->getKerning(), ), 'paragraph' => $this->getParagraph(), + 'rtl' => $this->isRTL(), 'shading' => $this->getShading(), ); @@ -730,6 +737,29 @@ class Font extends AbstractStyle return $this; } + /** + * Get rtl + * + * @return bool + */ + public function isRTL() + { + return $this->rtl; + } + + /** + * Set rtl + * + * @param bool $value + * @return self + */ + public function setRTL($value = true) + { + $this->rtl = $this->setBoolVal($value, $this->rtl); + + return $this; + } + /** * Get shading * diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 67a04829..9371f970 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -129,6 +129,12 @@ class Font extends AbstractStyle $styleWriter = new Shading($xmlWriter, $shading); $styleWriter->write(); } + + // RTL + if ($this->isInline === true) { + $styleName = $style->getStyleName(); + $xmlWriter->writeElementIf($styleName === null && $style->isRTL(), 'w:rtl'); + } $xmlWriter->endElement(); } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php new file mode 100644 index 00000000..af11c054 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php @@ -0,0 +1,54 @@ +addSection(); + $textrun = $section->addTextRun(); + $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $file = 'word/document.xml'; + $path = '/w:document/w:body/w:p/w:r/w:rPr/w:rtl'; + $this->assertTrue($doc->elementExists($path, $file)); + } +}

    Results: '; - foreach ($types as $type) { - $result = 'results/' . SCRIPT_FILENAME . '.' . $type; - if (file_exists($result)) { - echo "{$type} "; - } - } - echo '